From 79eb2da2460d9b87c758ebd486ba5e07e969e993 Mon Sep 17 00:00:00 2001 From: UselessBullets <80850784+UselessBullets@users.noreply.github.com> Date: Wed, 8 Nov 2023 15:43:39 -0600 Subject: [PATCH 01/13] Config overhaul (#8) * Allow for custom Config classes * Configuration Maps * new ManagedOreMethod * Replaced Parameters Enum with Parameters Class --- .../terrainapi/TerrainInitialization.java | 151 ++++++++---------- .../java/useless/terrainapi/TerrainMain.java | 6 +- .../useless/terrainapi/config/APIConfig.java | 11 ++ ...IConfigManager.java => ConfigManager.java} | 37 +++-- .../terrainapi/config/NetherConfig.java | 4 + .../useless/terrainapi/config/OreConfig.java | 32 ++++ .../terrainapi/config/OverworldConfig.java | 88 ++++++++++ .../terrainapi/config/TerrainAPIConfig.java | 21 --- .../generation/GeneratorFeatures.java | 6 +- .../terrainapi/generation/Parameters.java | 58 +++---- .../generation/StructureFeatures.java | 4 +- .../generation/VanillaFunctions.java | 145 ----------------- .../generation/nether/NetherFunctions.java | 9 ++ .../generation/nether/NetherOreFeatures.java | 4 +- .../{ => api}/ChunkDecoratorNetherAPI.java | 31 ++-- .../{ => api}/ChunkGeneratorNetherAPI.java | 2 +- .../overworld/OverworldBiomeFeatures.java | 11 +- .../overworld/OverworldFunctions.java | 118 ++++++++++++++ .../overworld/OverworldOreFeatures.java | 34 ++-- .../overworld/OverworldRandomFeatures.java | 6 +- .../{ => api}/ChunkDecoratorOverworldAPI.java | 43 +++-- .../{ => api}/ChunkGeneratorOverworldAPI.java | 2 +- .../overworld/{ => api}/MapGenCavesAPI.java | 2 +- .../mixin/WorldTypeOverworldMixin.java | 2 +- .../useless/terrainapi/util/Utilities.java | 23 +++ 25 files changed, 457 insertions(+), 393 deletions(-) create mode 100644 src/main/java/useless/terrainapi/config/APIConfig.java rename src/main/java/useless/terrainapi/config/{TerrainAPIConfigManager.java => ConfigManager.java} (62%) create mode 100644 src/main/java/useless/terrainapi/config/NetherConfig.java create mode 100644 src/main/java/useless/terrainapi/config/OreConfig.java create mode 100644 src/main/java/useless/terrainapi/config/OverworldConfig.java delete mode 100644 src/main/java/useless/terrainapi/config/TerrainAPIConfig.java delete mode 100644 src/main/java/useless/terrainapi/generation/VanillaFunctions.java create mode 100644 src/main/java/useless/terrainapi/generation/nether/NetherFunctions.java rename src/main/java/useless/terrainapi/generation/nether/{ => api}/ChunkDecoratorNetherAPI.java (75%) rename src/main/java/useless/terrainapi/generation/nether/{ => api}/ChunkGeneratorNetherAPI.java (92%) create mode 100644 src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java rename src/main/java/useless/terrainapi/generation/overworld/{ => api}/ChunkDecoratorOverworldAPI.java (84%) rename src/main/java/useless/terrainapi/generation/overworld/{ => api}/ChunkGeneratorOverworldAPI.java (92%) rename src/main/java/useless/terrainapi/generation/overworld/{ => api}/MapGenCavesAPI.java (99%) create mode 100644 src/main/java/useless/terrainapi/util/Utilities.java diff --git a/src/main/java/useless/terrainapi/TerrainInitialization.java b/src/main/java/useless/terrainapi/TerrainInitialization.java index c4e9c8c..5a523f4 100644 --- a/src/main/java/useless/terrainapi/TerrainInitialization.java +++ b/src/main/java/useless/terrainapi/TerrainInitialization.java @@ -5,21 +5,22 @@ import net.minecraft.core.world.biome.Biomes; import net.minecraft.core.world.generate.feature.*; import useless.terrainapi.api.TerrainAPI; +import useless.terrainapi.config.NetherConfig; +import useless.terrainapi.config.OverworldConfig; import useless.terrainapi.generation.Parameters; -import useless.terrainapi.generation.nether.ChunkDecoratorNetherAPI; -import useless.terrainapi.generation.overworld.ChunkDecoratorOverworldAPI; -import useless.terrainapi.generation.VanillaFunctions; -import useless.terrainapi.generation.overworld.OverworldBiomeFeatures; - -import java.util.HashMap; +import useless.terrainapi.generation.nether.NetherFunctions; +import useless.terrainapi.generation.nether.api.ChunkDecoratorNetherAPI; +import useless.terrainapi.generation.overworld.OverworldFunctions; +import useless.terrainapi.generation.overworld.api.ChunkDecoratorOverworldAPI; public class TerrainInitialization implements TerrainAPI { private static boolean hasInitialized = false; + private static final OverworldConfig overworldConfig = ChunkDecoratorOverworldAPI.overworldConfig; + private static final NetherConfig netherConfig = ChunkDecoratorNetherAPI.netherConfig; @Override public String getModID() { return TerrainMain.MOD_ID; } - @Override public void onInitialize() { if (hasInitialized) {return;} @@ -33,83 +34,67 @@ public void onInitialize() { initializeNether(); } - public static void initializeOverworldStructures() { - ChunkDecoratorOverworldAPI.structureFeatures.addStructure(VanillaFunctions::generateDungeons, null); - ChunkDecoratorOverworldAPI.structureFeatures.addStructure(VanillaFunctions::generateLabyrinths, null); - - } public static void initializeDefaultValues(){ - ChunkDecoratorOverworldAPI.oreFeatures.setOreValues(TerrainMain.MOD_ID, Block.blockClay, 32, 20, 1f); - ChunkDecoratorOverworldAPI.oreFeatures.setOreValues(TerrainMain.MOD_ID,Block.dirt, 32, 20, 1f); - ChunkDecoratorOverworldAPI.oreFeatures.setOreValues(TerrainMain.MOD_ID,Block.gravel, 32, 10, 1f); - ChunkDecoratorOverworldAPI.oreFeatures.setOreValues(TerrainMain.MOD_ID,Block.oreCoalStone, 16, 20, 1f); - ChunkDecoratorOverworldAPI.oreFeatures.setOreValues(TerrainMain.MOD_ID,Block.oreIronStone, 8, 20, 1/2f); - ChunkDecoratorOverworldAPI.oreFeatures.setOreValues(TerrainMain.MOD_ID,Block.oreGoldStone, 8, 2, 1/4f); - ChunkDecoratorOverworldAPI.oreFeatures.setOreValues(TerrainMain.MOD_ID,Block.oreRedstoneStone, 7, 8, 1/8f); - ChunkDecoratorOverworldAPI.oreFeatures.setOreValues(TerrainMain.MOD_ID,Block.oreDiamondStone, 7, 1, 1/8f); - ChunkDecoratorOverworldAPI.oreFeatures.setOreValues(TerrainMain.MOD_ID,Block.mossStone, 32, 1, 1/2f); - ChunkDecoratorOverworldAPI.oreFeatures.setOreValues(TerrainMain.MOD_ID,Block.oreLapisStone, 6, 1, 1/8f); - - OverworldBiomeFeatures.grassDensityMap.put(Biomes.OVERWORLD_FOREST, 2); - OverworldBiomeFeatures.grassDensityMap.put(Biomes.OVERWORLD_MEADOW, 2); - OverworldBiomeFeatures.grassDensityMap.put(Biomes.OVERWORLD_RAINFOREST, 10); - OverworldBiomeFeatures.grassDensityMap.put(Biomes.OVERWORLD_DESERT, 5); - OverworldBiomeFeatures.grassDensityMap.put(Biomes.OVERWORLD_SEASONAL_FOREST, 2); - OverworldBiomeFeatures.grassDensityMap.put(Biomes.OVERWORLD_TAIGA, 1); - OverworldBiomeFeatures.grassDensityMap.put(Biomes.OVERWORLD_BOREAL_FOREST, 5); - OverworldBiomeFeatures.grassDensityMap.put(Biomes.OVERWORLD_PLAINS, 10); - OverworldBiomeFeatures.grassDensityMap.put(Biomes.OVERWORLD_SWAMPLAND, 4); - OverworldBiomeFeatures.grassDensityMap.put(Biomes.OVERWORLD_SHRUBLAND, 2); - OverworldBiomeFeatures.grassDensityMap.put(Biomes.OVERWORLD_OUTBACK_GRASSY, 25); - OverworldBiomeFeatures.grassDensityMap.put(Biomes.OVERWORLD_BIRCH_FOREST, 10); + overworldConfig.setOreValues(TerrainMain.MOD_ID, Block.blockClay, 32, 20, 1f); - OverworldBiomeFeatures.flowerDensityMap.put(Biomes.OVERWORLD_SEASONAL_FOREST, 1); - OverworldBiomeFeatures.flowerDensityMap.put(Biomes.OVERWORLD_MEADOW, 2); - OverworldBiomeFeatures.flowerDensityMap.put(Biomes.OVERWORLD_BOREAL_FOREST, 2); - OverworldBiomeFeatures.flowerDensityMap.put(Biomes.OVERWORLD_SHRUBLAND, 1); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_FOREST, 2); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_MEADOW, 2); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_RAINFOREST, 10); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_DESERT, 5); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_SEASONAL_FOREST, 2); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_TAIGA, 1); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_BOREAL_FOREST, 5); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_PLAINS, 10); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_SWAMPLAND, 4); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_SHRUBLAND, 2); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_OUTBACK_GRASSY, 25); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_BIRCH_FOREST, 10); - OverworldBiomeFeatures.yellowFlowerDensityMap.put(Biomes.OVERWORLD_FOREST, 2); - OverworldBiomeFeatures.yellowFlowerDensityMap.put(Biomes.OVERWORLD_SWAMPLAND, 2); - OverworldBiomeFeatures.yellowFlowerDensityMap.put(Biomes.OVERWORLD_TAIGA, 2); - OverworldBiomeFeatures.yellowFlowerDensityMap.put(Biomes.OVERWORLD_PLAINS, 3); - OverworldBiomeFeatures.yellowFlowerDensityMap.put(Biomes.OVERWORLD_OUTBACK_GRASSY, 2); - OverworldBiomeFeatures.yellowFlowerDensityMap.put(Biomes.OVERWORLD_OUTBACK, 2); + overworldConfig.addFlowerDensity(Biomes.OVERWORLD_SEASONAL_FOREST, 1); + overworldConfig.addFlowerDensity(Biomes.OVERWORLD_MEADOW, 2); + overworldConfig.addFlowerDensity(Biomes.OVERWORLD_BOREAL_FOREST, 2); + overworldConfig.addFlowerDensity(Biomes.OVERWORLD_SHRUBLAND, 1); - OverworldBiomeFeatures.treeDensityMap.put(Biomes.OVERWORLD_FOREST, 5); - OverworldBiomeFeatures.treeDensityMap.put(Biomes.OVERWORLD_BIRCH_FOREST, 4); - OverworldBiomeFeatures.treeDensityMap.put(Biomes.OVERWORLD_RAINFOREST, 10); - OverworldBiomeFeatures.treeDensityMap.put(Biomes.OVERWORLD_SEASONAL_FOREST, 2); - OverworldBiomeFeatures.treeDensityMap.put(Biomes.OVERWORLD_TAIGA, 5); - OverworldBiomeFeatures.treeDensityMap.put(Biomes.OVERWORLD_BOREAL_FOREST, 3); - OverworldBiomeFeatures.treeDensityMap.put(Biomes.OVERWORLD_DESERT, -1000); - OverworldBiomeFeatures.treeDensityMap.put(Biomes.OVERWORLD_TUNDRA, -1000); - OverworldBiomeFeatures.treeDensityMap.put(Biomes.OVERWORLD_PLAINS, -1000); - OverworldBiomeFeatures.treeDensityMap.put(Biomes.OVERWORLD_SWAMPLAND, 4); - OverworldBiomeFeatures.treeDensityMap.put(Biomes.OVERWORLD_OUTBACK_GRASSY, 0); + overworldConfig.addYellowFlowerDensity(Biomes.OVERWORLD_FOREST, 2); + overworldConfig.addYellowFlowerDensity(Biomes.OVERWORLD_SWAMPLAND, 2); + overworldConfig.addYellowFlowerDensity(Biomes.OVERWORLD_TAIGA, 2); + overworldConfig.addYellowFlowerDensity(Biomes.OVERWORLD_PLAINS, 3); + overworldConfig.addYellowFlowerDensity(Biomes.OVERWORLD_OUTBACK_GRASSY, 2); + overworldConfig.addYellowFlowerDensity(Biomes.OVERWORLD_OUTBACK, 2); - VanillaFunctions.biomeRandomGrassType.put(Biomes.OVERWORLD_RAINFOREST, Block.tallgrassFern.id); - VanillaFunctions.biomeRandomGrassType.put(Biomes.OVERWORLD_SWAMPLAND, Block.tallgrassFern.id); - VanillaFunctions.biomeRandomGrassType.put(Biomes.OVERWORLD_BOREAL_FOREST, Block.tallgrassFern.id); - VanillaFunctions.biomeRandomGrassType.put(Biomes.OVERWORLD_TAIGA, Block.tallgrassFern.id); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_FOREST, 5); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_BIRCH_FOREST, 4); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_RAINFOREST, 10); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_SEASONAL_FOREST, 2); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_TAIGA, 5); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_BOREAL_FOREST, 3); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_DESERT, -1000); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_TUNDRA, -1000); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_PLAINS, -1000); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_SWAMPLAND, 4); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_OUTBACK_GRASSY, 0); - ChunkDecoratorNetherAPI.oreFeatures.setOreValues(TerrainMain.MOD_ID, Block.oreNethercoalNetherrack, 12, 10, 120/128f); + overworldConfig.addRandomGrassBlock(Biomes.OVERWORLD_RAINFOREST, Block.tallgrassFern); + overworldConfig.addRandomGrassBlock(Biomes.OVERWORLD_SWAMPLAND, Block.tallgrassFern); + overworldConfig.addRandomGrassBlock(Biomes.OVERWORLD_BOREAL_FOREST, Block.tallgrassFern); + overworldConfig.addRandomGrassBlock(Biomes.OVERWORLD_TAIGA, Block.tallgrassFern); + } + public static void initializeOverworldStructures() { + ChunkDecoratorOverworldAPI.structureFeatures.addStructure(OverworldFunctions::generateDungeons, null); + ChunkDecoratorOverworldAPI.structureFeatures.addStructure(OverworldFunctions::generateLabyrinths, null); } public static void initializeOverworldOre(){ - HashMap blockNumberMap = ChunkDecoratorOverworldAPI.overworldConfig.clusterSize; - HashMap chancesMap = ChunkDecoratorOverworldAPI.overworldConfig.chancesPerChunk; - HashMap rangeMap = ChunkDecoratorOverworldAPI.overworldConfig.verticalRange; - String currentBlock; - currentBlock = Block.blockClay.getKey(); - ChunkDecoratorOverworldAPI.oreFeatures.addFeature(new WorldFeatureClay(blockNumberMap.get(currentBlock)), chancesMap.get(currentBlock), rangeMap.get(currentBlock)); - ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(Block.dirt, false); - ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(Block.gravel, false); - ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(Block.oreCoalStone, true); - ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(Block.oreIronStone, true); - ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(Block.oreGoldStone, true); - ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(Block.oreRedstoneStone, true); - ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(Block.oreDiamondStone, true); - ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(Block.mossStone, true); - ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(Block.oreLapisStone, true); + String currentBlock = Block.blockClay.getKey(); + ChunkDecoratorOverworldAPI.oreFeatures.addFeature(new WorldFeatureClay(overworldConfig.clusterSize.get(currentBlock)), overworldConfig.chancesPerChunk.get(currentBlock), overworldConfig.verticalRange.get(currentBlock)); + ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.dirt, 32, 20, 1f, false); + ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.gravel, 32, 10, 1f, false); + ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.oreCoalStone, 16, 20, 1f, true); + ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.oreIronStone, 8, 20, 1/2f, true); + ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.oreGoldStone, 8, 2, 1/4f, true); + ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.oreRedstoneStone, 7, 8, 1/8f, true); + ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.oreDiamondStone, 7, 1, 1/8f, true); + ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.mossStone, 32, 1, 1/2f, true); + ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.oreLapisStone, 6, 1, 1/8f, true); } public static void initializeOverworldRandom(){ ChunkDecoratorOverworldAPI.randomFeatures.addFeature(new WorldFeatureFlowers(Block.flowerRed.id), 2, 1); @@ -121,20 +106,20 @@ public static void initializeOverworldRandom(){ } public static void initializeOverworldBiome(){ ChunkDecoratorOverworldAPI.biomeFeatures.addFeatureSurface(new WorldFeatureRichScorchedDirt(10), 1, new Biome[]{Biomes.OVERWORLD_OUTBACK, Biomes.OVERWORLD_OUTBACK_GRASSY}); - ChunkDecoratorOverworldAPI.biomeFeatures.addComplexFeature(VanillaFunctions::getTreeFeature, null, VanillaFunctions::getTreeDensity, null, -1f); + ChunkDecoratorOverworldAPI.biomeFeatures.addComplexFeature(OverworldFunctions::getTreeFeature, null, OverworldFunctions::getTreeDensity, null, -1f); ChunkDecoratorOverworldAPI.biomeFeatures.addFeatureSurface(new WorldFeatureSugarCaneTall(), 1, new Biome[]{Biomes.OVERWORLD_RAINFOREST}); - ChunkDecoratorOverworldAPI.biomeFeatures.addComplexFeature(VanillaFunctions::flowerTypeCondition, null, (Object[] x) -> OverworldBiomeFeatures.flowerDensityMap.getOrDefault(Parameters.getBiome(x), 0), null, 1f); - ChunkDecoratorOverworldAPI.biomeFeatures.addComplexFeature((Object[] x) -> new WorldFeatureFlowers(Block.flowerYellow.id), null, (Object[] x) -> OverworldBiomeFeatures.yellowFlowerDensityMap.getOrDefault(Parameters.getBiome(x), 0), null, 1); - ChunkDecoratorOverworldAPI.biomeFeatures.addComplexFeature(VanillaFunctions::grassTypeCondition, null, (Object[] x) -> OverworldBiomeFeatures.grassDensityMap.getOrDefault(Parameters.getBiome(x), 0), null, 1); + ChunkDecoratorOverworldAPI.biomeFeatures.addComplexFeature(OverworldFunctions::flowerTypeCondition, null, (Parameters x) -> ChunkDecoratorOverworldAPI.overworldConfig.getFlowerDensity(x.biome, 0), null, 1f); + ChunkDecoratorOverworldAPI.biomeFeatures.addComplexFeature((Parameters x) -> new WorldFeatureFlowers(Block.flowerYellow.id), null, (Parameters x) -> ChunkDecoratorOverworldAPI.overworldConfig.getYellowFlowerDensity(x.biome, 0), null, 1); + ChunkDecoratorOverworldAPI.biomeFeatures.addComplexFeature(OverworldFunctions::grassTypeCondition, null, (Parameters x) -> ChunkDecoratorOverworldAPI.overworldConfig.getGrassDensity(x.biome, 0), null, 1); ChunkDecoratorOverworldAPI.biomeFeatures.addFeature(new WorldFeatureSpinifexPatch(), 1, 4, new Biome[]{Biomes.OVERWORLD_OUTBACK}); ChunkDecoratorOverworldAPI.biomeFeatures.addFeature(new WorldFeatureDeadBush(Block.deadbush.id), 1, 2, new Biome[]{Biomes.OVERWORLD_DESERT}); ChunkDecoratorOverworldAPI.biomeFeatures.addFeature(new WorldFeatureCactus(), 1, 10, new Biome[]{Biomes.OVERWORLD_DESERT}); } public static void initializeNether(){ ChunkDecoratorNetherAPI.oreFeatures.addFeature(new WorldFeatureNetherLava(Block.fluidLavaFlowing.id), 8,120/128f); - ChunkDecoratorNetherAPI.oreFeatures.addManagedOreFeature(Block.oreNethercoalNetherrack, false); - ChunkDecoratorNetherAPI.oreFeatures.addComplexFeature((Object[] x) -> new WorldFeatureFire(), null, VanillaFunctions::netherFireDensity, null, 120/128f); - ChunkDecoratorNetherAPI.oreFeatures.addComplexFeature((Object[] x) -> new WorldFeatureGlowstoneA(), null, VanillaFunctions::netherFireDensity, null, 120/128f); + ChunkDecoratorNetherAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.oreNethercoalNetherrack, 12, 10, 120/128f, false); + ChunkDecoratorNetherAPI.oreFeatures.addComplexFeature((Parameters x) -> new WorldFeatureFire(), null, NetherFunctions::netherFireDensity, null, 120/128f); + ChunkDecoratorNetherAPI.oreFeatures.addComplexFeature((Parameters x) -> new WorldFeatureGlowstoneA(), null, NetherFunctions::netherFireDensity, null, 120/128f); ChunkDecoratorNetherAPI.oreFeatures.addFeature(new WorldFeatureGlowstoneB(), 10, 120/128f); ChunkDecoratorNetherAPI.randomFeatures.addFeature(new WorldFeatureLake(Block.fluidLavaStill.id), 8, 120/128f); } diff --git a/src/main/java/useless/terrainapi/TerrainMain.java b/src/main/java/useless/terrainapi/TerrainMain.java index 7e7f3dd..d251712 100644 --- a/src/main/java/useless/terrainapi/TerrainMain.java +++ b/src/main/java/useless/terrainapi/TerrainMain.java @@ -8,11 +8,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import useless.terrainapi.api.TerrainAPI; -import useless.terrainapi.config.TerrainAPIConfigManager; +import useless.terrainapi.config.ConfigManager; public class TerrainMain implements ModInitializer { - public static final Gson GSON = (new GsonBuilder()).setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).setPrettyPrinting().create(); + public static final Gson GSON = (new GsonBuilder()).setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create(); public static final String MOD_ID = "terrain-api"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); @Override @@ -28,6 +28,6 @@ public static void loadModules(){ } catch (NoSuchMethodException ignored) { } }); - TerrainAPIConfigManager.saveAll(); + ConfigManager.saveAll(); } } diff --git a/src/main/java/useless/terrainapi/config/APIConfig.java b/src/main/java/useless/terrainapi/config/APIConfig.java new file mode 100644 index 0000000..0dd13c5 --- /dev/null +++ b/src/main/java/useless/terrainapi/config/APIConfig.java @@ -0,0 +1,11 @@ +package useless.terrainapi.config; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; +public class APIConfig { + @SerializedName(value = "Override Default Values") @Expose + private boolean configOverride = false; + public boolean getConfigOverride(){ + return configOverride; + } +} diff --git a/src/main/java/useless/terrainapi/config/TerrainAPIConfigManager.java b/src/main/java/useless/terrainapi/config/ConfigManager.java similarity index 62% rename from src/main/java/useless/terrainapi/config/TerrainAPIConfigManager.java rename to src/main/java/useless/terrainapi/config/ConfigManager.java index f874084..096c934 100644 --- a/src/main/java/useless/terrainapi/config/TerrainAPIConfigManager.java +++ b/src/main/java/useless/terrainapi/config/ConfigManager.java @@ -5,14 +5,15 @@ import useless.terrainapi.TerrainMain; import java.io.*; +import java.lang.reflect.InvocationTargetException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; -public class TerrainAPIConfigManager { +public class ConfigManager { private static final HashMap fileHashMap = new HashMap<>(); - private static final HashMap configHashMap = new HashMap<>(); + private static final HashMap configHashMap = new HashMap<>(); private static void prepareBiomeConfigFile(String id) { if (fileHashMap.get(id) != null) { @@ -26,7 +27,7 @@ private static void prepareBiomeConfigFile(String id) { } fileHashMap.put(id, new File(filePath.toFile(), id + ".json")); } - private static void load(String id) { + private static void load(String id, Class clazz) { prepareBiomeConfigFile(id); try { @@ -35,8 +36,7 @@ private static void load(String id) { } if (fileHashMap.get(id).exists()) { BufferedReader br = new BufferedReader(new FileReader(fileHashMap.get(id))); - - configHashMap.put(id, TerrainMain.GSON.fromJson(br, TerrainAPIConfig.class)); + configHashMap.put(id, TerrainMain.GSON.fromJson(br, clazz)); save(id); } } catch (FileNotFoundException e) { @@ -48,7 +48,6 @@ public static void save(String id) { prepareBiomeConfigFile(id); String jsonString = TerrainMain.GSON.toJson(configHashMap.get(id)); - TerrainMain.LOGGER.info(jsonString); try (FileWriter fileWriter = new FileWriter(fileHashMap.get(id))) { fileWriter.write(jsonString); @@ -62,18 +61,22 @@ public static void saveAll(){ save(id); } } - public static TerrainAPIConfig getConfig(String id) { + public static T getConfig(String id, Class classOfT) { if (configHashMap.get(id) == null){ - configHashMap.put(id, new TerrainAPIConfig()); - } - load(id); - TerrainAPIConfig config = configHashMap.get(id); - if (config.getConfigOverride()){ - return configHashMap.getOrDefault(id, new TerrainAPIConfig()); - } else { - configHashMap.put(id, new TerrainAPIConfig()); - return configHashMap.get(id); + try { + configHashMap.put(id, classOfT.getDeclaredConstructor().newInstance()); + load(id, classOfT); + APIConfig config = configHashMap.get(id); + if (config.getConfigOverride()){ + return classOfT.cast(configHashMap.getOrDefault(id, classOfT.getDeclaredConstructor().newInstance())); + } else { + configHashMap.put(id, classOfT.getDeclaredConstructor().newInstance()); + return classOfT.cast(configHashMap.get(id)); + } + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + throw new RuntimeException(e); + } } - + return null; } } diff --git a/src/main/java/useless/terrainapi/config/NetherConfig.java b/src/main/java/useless/terrainapi/config/NetherConfig.java new file mode 100644 index 0000000..d273042 --- /dev/null +++ b/src/main/java/useless/terrainapi/config/NetherConfig.java @@ -0,0 +1,4 @@ +package useless.terrainapi.config; + +public class NetherConfig extends OreConfig{ +} diff --git a/src/main/java/useless/terrainapi/config/OreConfig.java b/src/main/java/useless/terrainapi/config/OreConfig.java new file mode 100644 index 0000000..7d7125b --- /dev/null +++ b/src/main/java/useless/terrainapi/config/OreConfig.java @@ -0,0 +1,32 @@ +package useless.terrainapi.config; + + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; +import net.minecraft.core.block.Block; +import useless.terrainapi.TerrainMain; + +import java.util.HashMap; + +public class OreConfig extends APIConfig { + @SerializedName(value = "Ore Cluster Size") @Expose + public HashMap clusterSize = new HashMap<>(); + @SerializedName(value = "Chances Per Chunk") @Expose + public HashMap chancesPerChunk = new HashMap<>(); + @SerializedName(value = "Vertical Range") @Expose + public HashMap verticalRange = new HashMap<>(); + public void setOreValues(String modID, Block block, int clusterSize, int chances, float range){ + if (this.clusterSize.get(block.getKey()) != null){ + TerrainMain.LOGGER.warn(modID + String.format(" has changed block %s to generate %d blocks with %d chances and a range of %f", block.getKey(), clusterSize, chances, range)); + } + setOreValues(block, clusterSize, chances, range); + } + protected void setOreValues(Block block, int clusterSize, int chances, float range){ + if (this.clusterSize.containsKey(block.getKey()) && this.getConfigOverride()){ + return; + } + this.clusterSize.put(block.getKey(), clusterSize); + this.chancesPerChunk.put(block.getKey(), chances); + this.verticalRange.put(block.getKey(), range); + } +} diff --git a/src/main/java/useless/terrainapi/config/OverworldConfig.java b/src/main/java/useless/terrainapi/config/OverworldConfig.java new file mode 100644 index 0000000..195d869 --- /dev/null +++ b/src/main/java/useless/terrainapi/config/OverworldConfig.java @@ -0,0 +1,88 @@ +package useless.terrainapi.config; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; +import net.minecraft.core.block.Block; +import net.minecraft.core.data.registry.Registries; +import net.minecraft.core.world.biome.Biome; + +import java.util.HashMap; + +public class OverworldConfig extends OreConfig{ + @Expose @SerializedName(value = "Biome Random Grass Block") + public HashMap biomeRandomGrassBlock = new HashMap<>(); + @Expose @SerializedName(value = "Grass Density") + public HashMap grassDensityMap = new HashMap<>(); + @Expose @SerializedName(value = "Flower Density") + public HashMap flowerDensityMap = new HashMap<>(); + @Expose @SerializedName(value = "Yellow Flower Density") + public HashMap yellowFlowerDensityMap = new HashMap<>(); + @Expose @SerializedName(value = "Tree Density") + public HashMap treeDensityMap = new HashMap<>(); + public void addRandomGrassBlock(Biome biome, Block block) { + if (getConfigOverride() && getRandomGrassBlock(biome) != null){ + return; + } + biomeRandomGrassBlock.put(Registries.BIOMES.getKey(biome), block.getKey()); + } + public Block getRandomGrassBlock(Biome biome){ + return Block.getBlockByName(biomeRandomGrassBlock.get(Registries.BIOMES.getKey(biome))); + } + public Block getRandomGrassBlock(Biome biome, Block defaultValue){ + Block returnBlock = Block.getBlockByName(biomeRandomGrassBlock.get(Registries.BIOMES.getKey(biome))); + if (returnBlock == null){ + returnBlock = defaultValue; + } + return returnBlock; + } + public void addGrassDensity(Biome biome, int density){ + if (getConfigOverride() && getGrassDensity(biome) != null){ + return; + } + grassDensityMap.put(Registries.BIOMES.getKey(biome), density); + } + public Integer getGrassDensity(Biome biome){ + return grassDensityMap.get(Registries.BIOMES.getKey(biome)); + } + public Integer getGrassDensity(Biome biome, int defaultValue){ + return grassDensityMap.getOrDefault(Registries.BIOMES.getKey(biome), defaultValue); + } + + public void addFlowerDensity(Biome biome, int density){ + if (getConfigOverride() && getFlowerDensity(biome) != null){ + return; + } + flowerDensityMap.put(Registries.BIOMES.getKey(biome), density); + } + public Integer getFlowerDensity(Biome biome){ + return flowerDensityMap.get(Registries.BIOMES.getKey(biome)); + } + public Integer getFlowerDensity(Biome biome, int defaultValue){ + return flowerDensityMap.getOrDefault(Registries.BIOMES.getKey(biome), defaultValue); + } + + public void addYellowFlowerDensity(Biome biome, int density){ + if (getConfigOverride() && getYellowFlowerDensity(biome) != null){ + return; + } + yellowFlowerDensityMap.put(Registries.BIOMES.getKey(biome), density); + } + public Integer getYellowFlowerDensity(Biome biome){ + return yellowFlowerDensityMap.get(Registries.BIOMES.getKey(biome)); + } + public Integer getYellowFlowerDensity(Biome biome, int defaultValue){ + return yellowFlowerDensityMap.getOrDefault(Registries.BIOMES.getKey(biome), defaultValue); + } + + public void addTreeDensity(Biome biome, int density){ + if (getConfigOverride() && getTreeDensity(biome) != null){ + return; + } + treeDensityMap.put(Registries.BIOMES.getKey(biome), density); + } + public Integer getTreeDensity(Biome biome){ + return treeDensityMap.get(Registries.BIOMES.getKey(biome)); + }public Integer getTreeDensity(Biome biome, int defaultValue){ + return treeDensityMap.getOrDefault(Registries.BIOMES.getKey(biome), defaultValue); + } +} diff --git a/src/main/java/useless/terrainapi/config/TerrainAPIConfig.java b/src/main/java/useless/terrainapi/config/TerrainAPIConfig.java deleted file mode 100644 index 6af60f9..0000000 --- a/src/main/java/useless/terrainapi/config/TerrainAPIConfig.java +++ /dev/null @@ -1,21 +0,0 @@ -package useless.terrainapi.config; - - -import com.google.gson.annotations.SerializedName; - -import java.util.HashMap; - -public class TerrainAPIConfig { - @SerializedName(value = "Override Default Values") - private boolean configOverride = false; - @SerializedName(value = "Ore Cluster Size") - public HashMap clusterSize = new HashMap<>(); - @SerializedName(value = "Chances Per Chunk") - public HashMap chancesPerChunk = new HashMap<>(); - @SerializedName(value = "Vertical Range") - public HashMap verticalRange = new HashMap<>(); - public boolean getConfigOverride(){ - return configOverride; - } - -} diff --git a/src/main/java/useless/terrainapi/generation/GeneratorFeatures.java b/src/main/java/useless/terrainapi/generation/GeneratorFeatures.java index 25b8440..e1b3e7e 100644 --- a/src/main/java/useless/terrainapi/generation/GeneratorFeatures.java +++ b/src/main/java/useless/terrainapi/generation/GeneratorFeatures.java @@ -7,16 +7,16 @@ import java.util.function.Function; public class GeneratorFeatures { - public List> featureFunctionsList = new ArrayList<>(); + public List> featureFunctionsList = new ArrayList<>(); public List featureParametersList = new ArrayList<>(); - public List> densityFunctionsList = new ArrayList<>(); + public List> densityFunctionsList = new ArrayList<>(); public List densityParametersList = new ArrayList<>(); /** The Object[] are the parameters passed into the provided function, index 0 will always be populated by Biome, index 1 with Random, index 2 with Chunk, index 3 with the ChunkDecorator, and index 4 with the oreHeightModifier. Additional parameters can be added in the method. * Range Modifier of -1 indicates that the feature should only generate on the surface * */ - public void addComplexFeature(Function featureFunction, Object[] featureParameters, Function densityFunction, Object[] densityParameters){ + public void addComplexFeature(Function featureFunction, Object[] featureParameters, Function densityFunction, Object[] densityParameters){ featureFunctionsList.add(featureFunction); featureParametersList.add(featureParameters); densityFunctionsList.add(densityFunction); diff --git a/src/main/java/useless/terrainapi/generation/Parameters.java b/src/main/java/useless/terrainapi/generation/Parameters.java index befb455..00103d1 100644 --- a/src/main/java/useless/terrainapi/generation/Parameters.java +++ b/src/main/java/useless/terrainapi/generation/Parameters.java @@ -7,47 +7,27 @@ import java.lang.reflect.Array; import java.util.Random; -public enum Parameters { - BIOME(0), - RANDOM(1), - CHUNK(2), - DECORATOR(3); - private static final int biggestID = 3; - public final int id; - private Parameters(int id){ - this.id = id; - } - public static Biome getBiome(Object[] parameters){ - return (Biome) parameters[BIOME.id]; - } - public static Random getRandom(Object[] parameters){ - return (Random) parameters[RANDOM.id]; - } - public static Chunk getChunk(Object[] parameters){ - return (Chunk) parameters[CHUNK.id]; - } - public static ChunkDecorator getDecorator(Object[] parameters){ - return (ChunkDecorator) parameters[DECORATOR.id]; +public class Parameters { + public Biome biome; + public Random random; + public Chunk chunk; + public ChunkDecorator decorator; + public Object[] customParameters = new Object[0]; + public Parameters(Biome biome, Random random, Chunk chunk, ChunkDecorator chunkDecorator, Object[] customParameters){ + this(biome, random, chunk, chunkDecorator); + this.customParameters = customParameters; + } + public Parameters(Biome biome, Random random, Chunk chunk, ChunkDecorator chunkDecorator){ + this.biome = biome; + this.random = random; + this.chunk = chunk; + this.decorator = chunkDecorator; + } + public Parameters(Parameters baseParameter, Object[] customParameters){ + this(baseParameter.biome, baseParameter.random, baseParameter.chunk, baseParameter.decorator); + this.customParameters = customParameters; } - /** - * @param parameters Object[] with preloaded parameters - * @param customIndex index into additional parameters, starts at index 1 - * @return Returns the selected custom parameter - */ - public static Object getCustomParameter(Object[] parameters, int customIndex){ - if (customIndex < 1) { - throw new NullPointerException("Custom Index must start from index 1 not 0!"); - } - return parameters[biggestID + customIndex]; - } - public static Object[] packParameters(Object[] base, Object[] customParameters){ - if (customParameters != null){ - Object[] parameters = base.clone(); - return concatenate(parameters, customParameters); - } - return base; - } public static T[] concatenate(T[] a, T[] b) { int aLen = a.length; int bLen = b.length; diff --git a/src/main/java/useless/terrainapi/generation/StructureFeatures.java b/src/main/java/useless/terrainapi/generation/StructureFeatures.java index b708916..d9bddf6 100644 --- a/src/main/java/useless/terrainapi/generation/StructureFeatures.java +++ b/src/main/java/useless/terrainapi/generation/StructureFeatures.java @@ -5,13 +5,13 @@ import java.util.function.Function; public class StructureFeatures extends GeneratorFeatures{ - public List> featureFunctionsList = new ArrayList<>(); + public List> featureFunctionsList = new ArrayList<>(); public List featureParametersList = new ArrayList<>(); /** The Object[] are the parameters passed into the provided function, index 0 will always be populated by Biome, index 1 with Random, index 2 with Chunk, index 3 with the ChunkDecorator, and index 4 with the oreHeightModifier. Additional parameters can be added in the method. * Range Modifier of -1 indicates that the feature should only generate on the surface * */ - public void addStructure(Function function, Object[] functionParameters){ + public void addStructure(Function function, Object[] functionParameters){ featureFunctionsList.add(function); featureParametersList.add(functionParameters); assert featureFunctionsList.size() == featureParametersList.size(): "Structure Features list sizes do not match!!"; diff --git a/src/main/java/useless/terrainapi/generation/VanillaFunctions.java b/src/main/java/useless/terrainapi/generation/VanillaFunctions.java deleted file mode 100644 index 0b658e4..0000000 --- a/src/main/java/useless/terrainapi/generation/VanillaFunctions.java +++ /dev/null @@ -1,145 +0,0 @@ -package useless.terrainapi.generation; - -import net.minecraft.core.block.Block; -import net.minecraft.core.world.biome.Biome; -import net.minecraft.core.world.chunk.Chunk; -import net.minecraft.core.world.generate.feature.WorldFeature; -import net.minecraft.core.world.generate.feature.WorldFeatureDungeon; -import net.minecraft.core.world.generate.feature.WorldFeatureLabyrinth; -import net.minecraft.core.world.generate.feature.WorldFeatureTallGrass; -import useless.terrainapi.generation.overworld.ChunkDecoratorOverworldAPI; -import useless.terrainapi.generation.overworld.OverworldBiomeFeatures; - -import java.util.HashMap; -import java.util.Random; - -public class VanillaFunctions { - public static HashMap biomeRandomGrassType = new HashMap<>(); - public static WorldFeature getTreeFeature(Object[] parameters){ - Biome biome = Parameters.getBiome(parameters); - Random random = Parameters.getRandom(parameters); - WorldFeature treeFeature = biome.getRandomWorldGenForTrees(random); - treeFeature.func_517_a(1.0, 1.0, 1.0); - return treeFeature; - } - public static int getTreeDensity(Object[] parameters){ - Biome biome = Parameters.getBiome(parameters); - ChunkDecoratorOverworldAPI decorator = (ChunkDecoratorOverworldAPI) Parameters.getDecorator(parameters); - - Integer treeDensity = OverworldBiomeFeatures.treeDensityMap.get(biome); - - if (decorator.treeDensityOverride != -1){ - return decorator.treeDensityOverride; - } - - if (treeDensity != null && treeDensity == -1000){ - return 0; - } else { - Random random = Parameters.getRandom(parameters); - Chunk chunk = Parameters.getChunk(parameters); - - int x = chunk.xPosition * 16; - int z = chunk.zPosition * 16; - double d = 0.5; - - int noiseValue = (int)((decorator.treeDensityNoise.get((double)x * d, (double)z * d) / 8.0 + random.nextDouble() * 4.0 + 4.0) / 3.0); - int treeDensityOffset = 0; - if (random.nextInt(10) == 0) { - ++treeDensityOffset; - } - if (treeDensity == null){ - return treeDensityOffset; - } - - return treeDensity + noiseValue + treeDensityOffset; - } - } - public static WorldFeature grassTypeCondition(Object[] parameters){ - Biome biome = Parameters.getBiome(parameters); - Random random = Parameters.getRandom(parameters); - - int blockId = Block.tallgrass.id; - if (checkForBiomeInBiomes(biome, biomeRandomGrassType.keySet().toArray(new Biome[0])) && random.nextInt(3) != 0) { - blockId = biomeRandomGrassType.get(biome); - } - return new WorldFeatureTallGrass(blockId); - } - public static WorldFeature flowerTypeCondition(Object[] parameters){ - Random random = Parameters.getRandom(parameters); - int blockId = Block.flowerYellow.id; - if (random.nextInt(3) != 0) { - blockId = Block.flowerRed.id; - } - return new WorldFeatureTallGrass(blockId); - } - public static int getStandardBiomesDensity(Object[] parameters){ - Biome biome = Parameters.getBiome(parameters); - int chance = (int) Parameters.getCustomParameter(parameters, 1); - Biome[] biomes = (Biome[]) Parameters.getCustomParameter(parameters, 2); - if (biomes == null) {return chance;} - if (checkForBiomeInBiomes(biome, biomes)){ - return chance; - } - return 0; - } - public static int getStandardOreBiomesDensity(Object[] parameters){ - Biome biome = Parameters.getBiome(parameters); - float oreHeightModifier = ((ChunkDecoratorOverworldAPI) Parameters.getDecorator(parameters)).oreHeightModifier; - int chance = (int) Parameters.getCustomParameter(parameters, 1); - Biome[] biomes = (Biome[]) Parameters.getCustomParameter(parameters, 2); - if (biomes == null) {return chance;} - if (checkForBiomeInBiomes(biome, biomes)){ - return (int) (chance * oreHeightModifier); - } - return 0; - } - public static Boolean generateDungeons(Object[] parameters){ - Random random = Parameters.getRandom(parameters); - Chunk chunk = Parameters.getChunk(parameters); - ChunkDecoratorOverworldAPI decorator = (ChunkDecoratorOverworldAPI) Parameters.getDecorator(parameters); - int x = chunk.xPosition * 16; - int z = chunk.zPosition * 16; - for (int i = 0; i < 8.0f * decorator.oreHeightModifier; i++) { - int xPos = x + random.nextInt(16) + 8; - int yPos = decorator.minY + random.nextInt(decorator.rangeY); - int zPos = z + random.nextInt(16) + 8; - if (random.nextInt(2) == 0){ - new WorldFeatureDungeon(Block.brickClay.id, Block.brickClay.id, null).generate(decorator.world, random, xPos, yPos, zPos); - } else { - new WorldFeatureDungeon(Block.cobbleStone.id, Block.cobbleStoneMossy.id, null).generate(decorator.world, random, xPos, yPos, zPos); - } - } - return true; - } - public static Boolean generateLabyrinths(Object[] parameters){ - Random random = Parameters.getRandom(parameters); - Chunk chunk = Parameters.getChunk(parameters); - ChunkDecoratorOverworldAPI decorator = (ChunkDecoratorOverworldAPI) Parameters.getDecorator(parameters); - int x = chunk.xPosition * 16; - int z = chunk.zPosition * 16; - for (int i = 0; i < 1; ++i) { - int xPos = x + random.nextInt(16) + 8; - int zPos = z + random.nextInt(16) + 8; - int yPos = decorator.world.getHeightValue(xPos, zPos) - (random.nextInt(2) + 2); - if (random.nextInt(5) == 0) { - yPos -= random.nextInt(10) + 30; - } - if (random.nextInt(700) != 0) continue; - Random lRand = chunk.getChunkRandom(75644760L); - new WorldFeatureLabyrinth().generate(decorator.world, lRand, xPos, yPos, zPos); - } - return true; - } - public static int netherFireDensity(Object[] parameters){ - Random random = Parameters.getRandom(parameters); - return random.nextInt(random.nextInt(10) + 1); - } - public static boolean checkForBiomeInBiomes(Biome biome, Biome[] biomes){ - for (Biome checkBiome: biomes) { - if (biome.equals(checkBiome)){ - return true; - } - } - return false; - } -} diff --git a/src/main/java/useless/terrainapi/generation/nether/NetherFunctions.java b/src/main/java/useless/terrainapi/generation/nether/NetherFunctions.java new file mode 100644 index 0000000..bca8480 --- /dev/null +++ b/src/main/java/useless/terrainapi/generation/nether/NetherFunctions.java @@ -0,0 +1,9 @@ +package useless.terrainapi.generation.nether; + +import useless.terrainapi.generation.Parameters; + +public class NetherFunctions { + public static int netherFireDensity(Parameters parameters){ + return parameters.random.nextInt(parameters.random.nextInt(10) + 1); + } +} diff --git a/src/main/java/useless/terrainapi/generation/nether/NetherOreFeatures.java b/src/main/java/useless/terrainapi/generation/nether/NetherOreFeatures.java index ef0d787..ebc5400 100644 --- a/src/main/java/useless/terrainapi/generation/nether/NetherOreFeatures.java +++ b/src/main/java/useless/terrainapi/generation/nether/NetherOreFeatures.java @@ -1,10 +1,10 @@ package useless.terrainapi.generation.nether; -import useless.terrainapi.config.TerrainAPIConfig; +import useless.terrainapi.config.OreConfig; import useless.terrainapi.generation.overworld.OverworldOreFeatures; public class NetherOreFeatures extends OverworldOreFeatures { - public NetherOreFeatures(TerrainAPIConfig config) { + public NetherOreFeatures(OreConfig config) { super(config); } } diff --git a/src/main/java/useless/terrainapi/generation/nether/ChunkDecoratorNetherAPI.java b/src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java similarity index 75% rename from src/main/java/useless/terrainapi/generation/nether/ChunkDecoratorNetherAPI.java rename to src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java index d4648d1..dbe2972 100644 --- a/src/main/java/useless/terrainapi/generation/nether/ChunkDecoratorNetherAPI.java +++ b/src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java @@ -1,25 +1,28 @@ -package useless.terrainapi.generation.nether; +package useless.terrainapi.generation.nether.api; import net.minecraft.core.block.BlockSand; import net.minecraft.core.world.World; import net.minecraft.core.world.biome.Biome; import net.minecraft.core.world.chunk.Chunk; -import net.minecraft.core.world.generate.feature.*; -import useless.terrainapi.config.TerrainAPIConfig; -import useless.terrainapi.config.TerrainAPIConfigManager; +import net.minecraft.core.world.generate.feature.WorldFeature; +import useless.terrainapi.config.ConfigManager; +import useless.terrainapi.config.NetherConfig; import useless.terrainapi.generation.ChunkDecoratorAPI; import useless.terrainapi.generation.Parameters; import useless.terrainapi.generation.StructureFeatures; +import useless.terrainapi.generation.nether.NetherBiomeFeatures; +import useless.terrainapi.generation.nether.NetherOreFeatures; +import useless.terrainapi.generation.nether.NetherRandomFeatures; import java.util.Random; public class ChunkDecoratorNetherAPI extends ChunkDecoratorAPI { - public static TerrainAPIConfig netherConfig = TerrainAPIConfigManager.getConfig("nether"); + public static NetherConfig netherConfig = ConfigManager.getConfig("nether", NetherConfig.class); public static StructureFeatures structureFeatures = new StructureFeatures(); public static NetherOreFeatures oreFeatures = new NetherOreFeatures(netherConfig); public static NetherRandomFeatures randomFeatures = new NetherRandomFeatures(); public static NetherBiomeFeatures biomeFeatures = new NetherBiomeFeatures(); - private Object[] parameterBase; + private Parameters parameterBase; protected ChunkDecoratorNetherAPI(World world) { super(world); } @@ -37,7 +40,7 @@ public void decorate(Chunk chunk) { BlockSand.fallInstantly = true; - parameterBase = new Object[]{biome, random, chunk, this}; + parameterBase = new Parameters(biome, random, chunk, this); generateStructures(biome, chunk, structureRand); generateOreFeatures(biome, xCoord, zCoord, random, chunk); @@ -51,17 +54,17 @@ public void generateStructures(Biome biome, Chunk chunk, Random random){ int featureSize = structureFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { structureFeatures.featureFunctionsList.get(i) - .apply(Parameters.packParameters(parameterBase, structureFeatures.featureParametersList.get(i))); + .apply(new Parameters(parameterBase, structureFeatures.featureParametersList.get(i))); } } public void generateOreFeatures(Biome biome, int x, int z, Random random, Chunk chunk){ int featureSize = oreFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { WorldFeature feature = oreFeatures.featureFunctionsList.get(i) - .apply(Parameters.packParameters(parameterBase, oreFeatures.featureParametersList.get(i))); + .apply(new Parameters(parameterBase, oreFeatures.featureParametersList.get(i))); int density = oreFeatures.densityFunctionsList.get(i) - .apply(Parameters.packParameters(parameterBase, oreFeatures.densityParametersList.get(i))); + .apply(new Parameters(parameterBase, oreFeatures.densityParametersList.get(i))); float rangeModifier = oreFeatures.rangeModifierList.get(i); generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, random); @@ -72,10 +75,10 @@ public void generateRandomFeatures(Biome biome, int x, int z, Random random, Chu for (int i = 0; i < featureSize; i++) { if (random.nextInt(randomFeatures.inverseProbabilityList.get(i)) != 0) {continue;} WorldFeature feature = randomFeatures.featureFunctionsList.get(i) - .apply(Parameters.packParameters(parameterBase, randomFeatures.featureParametersList.get(i))); + .apply(new Parameters(parameterBase, randomFeatures.featureParametersList.get(i))); int density = randomFeatures.densityFunctionsList.get(i) - .apply(Parameters.packParameters(parameterBase, randomFeatures.densityParametersList.get(i))); + .apply(new Parameters(parameterBase, randomFeatures.densityParametersList.get(i))); float rangeModifier = randomFeatures.rangeModifierList.get(i); if (-1.01 <= rangeModifier && rangeModifier <= -0.99){ @@ -89,10 +92,10 @@ public void generateBiomeFeature(Biome biome, int x, int z, Random random, Chunk int featureSize = biomeFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { WorldFeature feature = biomeFeatures.featureFunctionsList.get(i) - .apply(Parameters.packParameters(parameterBase, biomeFeatures.featureParametersList.get(i))); + .apply(new Parameters(parameterBase, biomeFeatures.featureParametersList.get(i))); int density = biomeFeatures.densityFunctionsList.get(i) - .apply(Parameters.packParameters(parameterBase, biomeFeatures.densityParametersList.get(i))); + .apply(new Parameters(parameterBase, biomeFeatures.densityParametersList.get(i))); float rangeModifier = biomeFeatures.rangeModifierList.get(i); if (-1.01 <= rangeModifier && rangeModifier <= -0.99){ diff --git a/src/main/java/useless/terrainapi/generation/nether/ChunkGeneratorNetherAPI.java b/src/main/java/useless/terrainapi/generation/nether/api/ChunkGeneratorNetherAPI.java similarity index 92% rename from src/main/java/useless/terrainapi/generation/nether/ChunkGeneratorNetherAPI.java rename to src/main/java/useless/terrainapi/generation/nether/api/ChunkGeneratorNetherAPI.java index a695be0..4f9de65 100644 --- a/src/main/java/useless/terrainapi/generation/nether/ChunkGeneratorNetherAPI.java +++ b/src/main/java/useless/terrainapi/generation/nether/api/ChunkGeneratorNetherAPI.java @@ -1,4 +1,4 @@ -package useless.terrainapi.generation.nether; +package useless.terrainapi.generation.nether.api; import net.minecraft.core.world.World; import net.minecraft.core.world.generate.MapGenCavesHell; diff --git a/src/main/java/useless/terrainapi/generation/overworld/OverworldBiomeFeatures.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldBiomeFeatures.java index 28f826d..693053c 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/OverworldBiomeFeatures.java +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldBiomeFeatures.java @@ -3,31 +3,26 @@ import net.minecraft.core.world.biome.Biome; import net.minecraft.core.world.generate.feature.WorldFeature; import useless.terrainapi.generation.GeneratorFeatures; -import useless.terrainapi.generation.VanillaFunctions; +import useless.terrainapi.generation.Parameters; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.function.Function; public class OverworldBiomeFeatures extends GeneratorFeatures { - public static HashMap grassDensityMap = new HashMap<>(); - public static HashMap flowerDensityMap = new HashMap<>(); - public static HashMap yellowFlowerDensityMap = new HashMap<>(); - public static HashMap treeDensityMap = new HashMap<>(); public List rangeModifierList = new ArrayList<>(); public void addFeatureSurface(WorldFeature feature, int chances, Biome[] biomes){ addFeature(feature, -1f, chances, biomes); } public void addFeature(WorldFeature feature, float rangeModifier, int chances, Biome[] biomes){ - addComplexFeature((Object[] x) -> feature, null, VanillaFunctions::getStandardBiomesDensity, new Object[]{chances, biomes}, rangeModifier); + addComplexFeature((Parameters x) -> feature, null, OverworldFunctions::getStandardBiomesDensity, new Object[]{chances, biomes}, rangeModifier); } /** The Object[] are the parameters passed into the provided function, index 0 will always be populated by Biome, index 1 with Random, index 2 with Chunk, and index 3 with the ChunkDecorator. Additional parameters can be added in the method. * Range Modifier of -1 indicates that the feature should only generate on the surface * */ - public void addComplexFeature(Function featureFunction, Object[] featureParameters, Function densityFunction, Object[] densityParameters, float rangeModifier){ + public void addComplexFeature(Function featureFunction, Object[] featureParameters, Function densityFunction, Object[] densityParameters, float rangeModifier){ super.addComplexFeature(featureFunction, featureParameters, densityFunction, densityParameters); rangeModifierList.add(rangeModifier); } diff --git a/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java new file mode 100644 index 0000000..12ff478 --- /dev/null +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java @@ -0,0 +1,118 @@ +package useless.terrainapi.generation.overworld; + +import net.minecraft.core.block.Block; +import net.minecraft.core.world.biome.Biome; +import net.minecraft.core.world.chunk.Chunk; +import net.minecraft.core.world.generate.feature.WorldFeature; +import net.minecraft.core.world.generate.feature.WorldFeatureDungeon; +import net.minecraft.core.world.generate.feature.WorldFeatureLabyrinth; +import net.minecraft.core.world.generate.feature.WorldFeatureTallGrass; +import useless.terrainapi.config.OverworldConfig; +import useless.terrainapi.generation.Parameters; +import useless.terrainapi.generation.overworld.api.ChunkDecoratorOverworldAPI; +import useless.terrainapi.util.Utilities; + +import java.util.Random; + +public class OverworldFunctions { + public static OverworldConfig overworldConfig = ChunkDecoratorOverworldAPI.overworldConfig; + public static WorldFeature getTreeFeature(Parameters parameters){ + WorldFeature treeFeature = parameters.biome.getRandomWorldGenForTrees(parameters.random); + treeFeature.func_517_a(1.0, 1.0, 1.0); + return treeFeature; + } + public static int getTreeDensity(Parameters parameters){ + ChunkDecoratorOverworldAPI decorator = (ChunkDecoratorOverworldAPI) parameters.decorator; + + Integer treeDensity = overworldConfig.getTreeDensity(parameters.biome); + + if (decorator.treeDensityOverride != -1){ + return decorator.treeDensityOverride; + } + + if (treeDensity != null && treeDensity == -1000){ + return 0; + } else { + int x = parameters.chunk.xPosition * 16; + int z = parameters.chunk.zPosition * 16; + double d = 0.5; + + int noiseValue = (int)((decorator.treeDensityNoise.get((double)x * d, (double)z * d) / 8.0 + parameters.random.nextDouble() * 4.0 + 4.0) / 3.0); + int treeDensityOffset = 0; + if (parameters.random.nextInt(10) == 0) { + ++treeDensityOffset; + } + if (treeDensity == null){ + return treeDensityOffset; + } + + return treeDensity + noiseValue + treeDensityOffset; + } + } + public static WorldFeature grassTypeCondition(Parameters parameters){ + Block block = Block.tallgrass; + if (Utilities.checkForBiomeInBiomes(parameters.biome, overworldConfig.biomeRandomGrassBlock.keySet().toArray(new String[0])) && parameters.random.nextInt(3) != 0) { + block = overworldConfig.getRandomGrassBlock(parameters.biome); + } + return new WorldFeatureTallGrass(block.id); + } + public static WorldFeature flowerTypeCondition(Parameters parameters){ + int blockId = Block.flowerYellow.id; + if (parameters.random.nextInt(3) != 0) { + blockId = Block.flowerRed.id; + } + return new WorldFeatureTallGrass(blockId); + } + public static int getStandardBiomesDensity(Parameters parameters){ + int chance = (int) parameters.customParameters[0]; + Biome[] biomes = (Biome[]) parameters.customParameters[1]; + if (biomes == null) {return chance;} + if (Utilities.checkForBiomeInBiomes(parameters.biome, biomes)){ + return chance; + } + return 0; + } + public static int getStandardOreBiomesDensity(Parameters parameters){ + float oreHeightModifier = ((ChunkDecoratorOverworldAPI) parameters.decorator).oreHeightModifier; + int chance = (int) parameters.customParameters[0]; + Biome[] biomes = (Biome[]) parameters.customParameters[1]; + if (biomes == null) {return chance;} + if (Utilities.checkForBiomeInBiomes(parameters.biome, biomes)){ + return (int) (chance * oreHeightModifier); + } + return 0; + } + public static Boolean generateDungeons(Parameters parameters){ + int x = parameters.chunk.xPosition * 16; + int z = parameters.chunk.zPosition * 16; + ChunkDecoratorOverworldAPI decoratorOverworldAPI = (ChunkDecoratorOverworldAPI) parameters.decorator; + for (int i = 0; i < 8.0f * decoratorOverworldAPI.oreHeightModifier; i++) { + int xPos = x + parameters.random.nextInt(16) + 8; + int yPos = decoratorOverworldAPI.minY + parameters.random.nextInt(decoratorOverworldAPI.rangeY); + int zPos = z + parameters.random.nextInt(16) + 8; + if (parameters.random.nextInt(2) == 0){ + new WorldFeatureDungeon(Block.brickClay.id, Block.brickClay.id, null).generate(decoratorOverworldAPI.world, parameters.random, xPos, yPos, zPos); + } else { + new WorldFeatureDungeon(Block.cobbleStone.id, Block.cobbleStoneMossy.id, null).generate(decoratorOverworldAPI.world, parameters.random, xPos, yPos, zPos); + } + } + return true; + } + public static Boolean generateLabyrinths(Parameters parameters){ + ChunkDecoratorOverworldAPI decorator = (ChunkDecoratorOverworldAPI) parameters.decorator; + int x = parameters.chunk.xPosition * 16; + int z = parameters.chunk.zPosition * 16; + for (int i = 0; i < 1; ++i) { + int xPos = x + parameters.random.nextInt(16) + 8; + int zPos = z + parameters.random.nextInt(16) + 8; + int yPos = decorator.world.getHeightValue(xPos, zPos) - (parameters.random.nextInt(2) + 2); + if (parameters.random.nextInt(5) == 0) { + yPos -= parameters.random.nextInt(10) + 30; + } + if (parameters.random.nextInt(700) != 0) continue; + Random lRand = parameters.chunk.getChunkRandom(75644760L); + new WorldFeatureLabyrinth().generate(decorator.world, lRand, xPos, yPos, zPos); + } + return true; + } +} diff --git a/src/main/java/useless/terrainapi/generation/overworld/OverworldOreFeatures.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldOreFeatures.java index 915eebe..e19a968 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/OverworldOreFeatures.java +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldOreFeatures.java @@ -4,53 +4,37 @@ import net.minecraft.core.world.biome.Biome; import net.minecraft.core.world.generate.feature.WorldFeature; import net.minecraft.core.world.generate.feature.WorldFeatureOre; -import useless.terrainapi.TerrainMain; -import useless.terrainapi.config.TerrainAPIConfig; +import useless.terrainapi.config.OreConfig; import useless.terrainapi.generation.GeneratorFeatures; -import useless.terrainapi.generation.VanillaFunctions; +import useless.terrainapi.generation.Parameters; -import java.awt.*; import java.util.ArrayList; import java.util.List; import java.util.function.Function; public class OverworldOreFeatures extends GeneratorFeatures { public List rangeModifierList = new ArrayList<>(); - public TerrainAPIConfig config; - public OverworldOreFeatures(TerrainAPIConfig config){ + public OreConfig config; + public OverworldOreFeatures(OreConfig config){ this.config = config; } public void addFeature(WorldFeature feature, int chances, float rangeModifier){ addFeature(feature, chances, rangeModifier, null); } public void addFeature(WorldFeature feature, int chances, float rangeModifier, Biome[] biomes){ - addComplexFeature((Object[] x) -> feature, null, VanillaFunctions::getStandardOreBiomesDensity, new Object[]{chances, biomes}, rangeModifier); + addComplexFeature((Parameters x) -> feature, null, OverworldFunctions::getStandardOreBiomesDensity, new Object[]{chances, biomes}, rangeModifier); } /** The Object[] are the parameters passed into the provided function, index 0 will always be populated by Biome, index 1 with Random, index 2 with Chunk, index 3 with the ChunkDecorator, and index 4 with the oreHeightModifier. Additional parameters can be added in the method. * Range Modifier of -1 indicates that the feature should only generate on the surface * */ - public void addComplexFeature(Function featureFunction, Object[] featureParameters, Function densityFunction, Object[] densityParameters, float rangeModifier){ + public void addComplexFeature(Function featureFunction, Object[] featureParameters, Function densityFunction, Object[] densityParameters, float rangeModifier){ super.addComplexFeature(featureFunction, featureParameters, densityFunction, densityParameters); rangeModifierList.add(rangeModifier); } - @Deprecated - public void setOreValues(String modID, int blockID, int clusterSize, int chances, float range){ - setOreValues(modID, Block.getBlock(blockID), clusterSize, chances, range); - } - public void setOreValues(String modID, Block block, int clusterSize, int chances, float range){ - if (config.clusterSize.get(block.getKey()) != null){ - TerrainMain.LOGGER.warn(modID + String.format(" has changed block %s to generate %d blocks with %d chances and a range of %f", block.getKey(), clusterSize, chances, range)); - } - setOreValues(block, clusterSize, chances, range); - } - protected void setOreValues(Block block, int clusterSize, int chances, float range){ - if (config.clusterSize.containsKey(block.getKey()) && config.getConfigOverride()){ - return; - } - config.clusterSize.put(block.getKey(), clusterSize); - config.chancesPerChunk.put(block.getKey(), chances); - config.verticalRange.put(block.getKey(), range); + public void addManagedOreFeature(String modID, Block block, int defaultClusterSize, int defaultChances, float defaultRange, boolean hasStoneStates){ + config.setOreValues(modID, block, defaultClusterSize, defaultChances, defaultRange); + addManagedOreFeature(block, hasStoneStates); } public void addManagedOreFeature(Block block, boolean hasStoneStates){ String currentBlock = block.getKey(); diff --git a/src/main/java/useless/terrainapi/generation/overworld/OverworldRandomFeatures.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldRandomFeatures.java index 49d0ab5..39e9226 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/OverworldRandomFeatures.java +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldRandomFeatures.java @@ -3,7 +3,7 @@ import net.minecraft.core.world.biome.Biome; import net.minecraft.core.world.generate.feature.WorldFeature; import useless.terrainapi.generation.GeneratorFeatures; -import useless.terrainapi.generation.VanillaFunctions; +import useless.terrainapi.generation.Parameters; import java.util.ArrayList; import java.util.List; @@ -19,13 +19,13 @@ public void addFeature(WorldFeature feature, int inverseProbability, float range addFeature(feature, inverseProbability, rangeModifier,1, null); } public void addFeature(WorldFeature feature, int inverseProbability, float rangeModifier, int chances, Biome[] biomes){ - addComplexFeature((Object[] x) -> feature, null, VanillaFunctions::getStandardBiomesDensity, new Object[]{chances, biomes}, inverseProbability, rangeModifier); + addComplexFeature((Parameters x) -> feature, null, OverworldFunctions::getStandardBiomesDensity, new Object[]{chances, biomes}, inverseProbability, rangeModifier); } /** The Object[] are the parameters passed into the provided function, index 0 will always be populated by Biome, index 1 with Random, index 2 with Chunk, and index 3 with the ChunkDecorator. Additional parameters can be added in the method. * Range Modifier of -1 indicates that the feature should only generate on the surface * */ - public void addComplexFeature(Function featureFunction, Object[] featureParameters, Function densityFunction, Object[] densityParameters,int inverseProbability, float rangeModifier){ + public void addComplexFeature(Function featureFunction, Object[] featureParameters, Function densityFunction, Object[] densityParameters, int inverseProbability, float rangeModifier){ super.addComplexFeature(featureFunction, featureParameters, densityFunction, densityParameters); rangeModifierList.add(rangeModifier); inverseProbabilityList.add(inverseProbability); diff --git a/src/main/java/useless/terrainapi/generation/overworld/ChunkDecoratorOverworldAPI.java b/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java similarity index 84% rename from src/main/java/useless/terrainapi/generation/overworld/ChunkDecoratorOverworldAPI.java rename to src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java index 5dd0e7c..6eef8eb 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/ChunkDecoratorOverworldAPI.java +++ b/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java @@ -1,4 +1,4 @@ -package useless.terrainapi.generation.overworld; +package useless.terrainapi.generation.overworld.api; import net.minecraft.core.block.Block; import net.minecraft.core.block.BlockSand; @@ -7,36 +7,31 @@ import net.minecraft.core.world.biome.Biome; import net.minecraft.core.world.biome.Biomes; import net.minecraft.core.world.chunk.Chunk; -import net.minecraft.core.world.generate.feature.*; +import net.minecraft.core.world.generate.feature.WorldFeature; +import net.minecraft.core.world.generate.feature.WorldFeatureLake; +import net.minecraft.core.world.generate.feature.WorldFeatureLiquid; import net.minecraft.core.world.noise.PerlinNoise; -import useless.terrainapi.config.TerrainAPIConfig; -import useless.terrainapi.config.TerrainAPIConfigManager; +import useless.terrainapi.config.ConfigManager; +import useless.terrainapi.config.OverworldConfig; import useless.terrainapi.generation.ChunkDecoratorAPI; import useless.terrainapi.generation.Parameters; import useless.terrainapi.generation.StructureFeatures; +import useless.terrainapi.generation.overworld.OverworldBiomeFeatures; +import useless.terrainapi.generation.overworld.OverworldOreFeatures; +import useless.terrainapi.generation.overworld.OverworldRandomFeatures; import java.util.Random; public class ChunkDecoratorOverworldAPI extends ChunkDecoratorAPI { - public static TerrainAPIConfig overworldConfig = TerrainAPIConfigManager.getConfig("overworld"); + public static OverworldConfig overworldConfig = ConfigManager.getConfig("overworld", OverworldConfig.class); public final PerlinNoise treeDensityNoise; public final int treeDensityOverride; private final int lakeDensityDefault = 4; - private Object[] parameterBase; + private Parameters parameterBase; public static StructureFeatures structureFeatures = new StructureFeatures(); public static OverworldOreFeatures oreFeatures = new OverworldOreFeatures(overworldConfig); public static OverworldRandomFeatures randomFeatures = new OverworldRandomFeatures(); public static OverworldBiomeFeatures biomeFeatures = new OverworldBiomeFeatures(); - @Deprecated - public static StructureFeatures StructureFeatures = structureFeatures; - @Deprecated - public static OverworldOreFeatures OreFeatures = oreFeatures; - @Deprecated - public static OverworldRandomFeatures RandomFeatures = randomFeatures; - @Deprecated - public static OverworldBiomeFeatures BiomeFeatures = biomeFeatures; - - protected ChunkDecoratorOverworldAPI(World world, int treeDensityOverride) { super(world); this.treeDensityOverride = treeDensityOverride; @@ -70,7 +65,7 @@ public void decorate(Chunk chunk) { } int lakeChance = getLakeChance(biome); - parameterBase = new Object[]{biome, random, chunk, this}; + parameterBase = new Parameters(biome, random, chunk, this); generateLakeFeature(lakeChance, xCoord, zCoord, biome, random); @@ -140,17 +135,17 @@ public void generateStructures(Biome biome, Chunk chunk, Random random){ int featureSize = structureFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { structureFeatures.featureFunctionsList.get(i) - .apply(Parameters.packParameters(parameterBase, structureFeatures.featureParametersList.get(i))); + .apply(new Parameters(parameterBase, structureFeatures.featureParametersList.get(i))); } } public void generateOreFeatures(Biome biome, int x, int z, Random random, Chunk chunk){ int featureSize = oreFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { WorldFeature feature = oreFeatures.featureFunctionsList.get(i) - .apply(Parameters.packParameters(parameterBase, oreFeatures.featureParametersList.get(i))); + .apply(new Parameters(parameterBase, oreFeatures.featureParametersList.get(i))); int density = oreFeatures.densityFunctionsList.get(i) - .apply(Parameters.packParameters(parameterBase, oreFeatures.densityParametersList.get(i))); + .apply(new Parameters(parameterBase, oreFeatures.densityParametersList.get(i))); float rangeModifier = oreFeatures.rangeModifierList.get(i); generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, random); @@ -161,10 +156,10 @@ public void generateRandomFeatures(Biome biome, int x, int z, Random random, Chu for (int i = 0; i < featureSize; i++) { if (random.nextInt(randomFeatures.inverseProbabilityList.get(i)) != 0) {continue;} WorldFeature feature = randomFeatures.featureFunctionsList.get(i) - .apply(Parameters.packParameters(parameterBase, randomFeatures.featureParametersList.get(i))); + .apply(new Parameters(parameterBase, randomFeatures.featureParametersList.get(i))); int density = randomFeatures.densityFunctionsList.get(i) - .apply(Parameters.packParameters(parameterBase, randomFeatures.densityParametersList.get(i))); + .apply(new Parameters(parameterBase, randomFeatures.densityParametersList.get(i))); float rangeModifier = randomFeatures.rangeModifierList.get(i); if (-1.01 <= rangeModifier && rangeModifier <= -0.99){ @@ -178,10 +173,10 @@ public void generateBiomeFeature(Biome biome, int x, int z, Random random, Chunk int featureSize = biomeFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { WorldFeature feature = biomeFeatures.featureFunctionsList.get(i) - .apply(Parameters.packParameters(parameterBase, biomeFeatures.featureParametersList.get(i))); + .apply(new Parameters(parameterBase, biomeFeatures.featureParametersList.get(i))); int density = biomeFeatures.densityFunctionsList.get(i) - .apply(Parameters.packParameters(parameterBase, biomeFeatures.densityParametersList.get(i))); + .apply(new Parameters(parameterBase, biomeFeatures.densityParametersList.get(i))); float rangeModifier = biomeFeatures.rangeModifierList.get(i); if (-1.01 <= rangeModifier && rangeModifier <= -0.99){ diff --git a/src/main/java/useless/terrainapi/generation/overworld/ChunkGeneratorOverworldAPI.java b/src/main/java/useless/terrainapi/generation/overworld/api/ChunkGeneratorOverworldAPI.java similarity index 92% rename from src/main/java/useless/terrainapi/generation/overworld/ChunkGeneratorOverworldAPI.java rename to src/main/java/useless/terrainapi/generation/overworld/api/ChunkGeneratorOverworldAPI.java index 2071dfa..c2a396f 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/ChunkGeneratorOverworldAPI.java +++ b/src/main/java/useless/terrainapi/generation/overworld/api/ChunkGeneratorOverworldAPI.java @@ -1,4 +1,4 @@ -package useless.terrainapi.generation.overworld; +package useless.terrainapi.generation.overworld.api; import net.minecraft.core.world.World; import net.minecraft.core.world.generate.MapGenCaves; diff --git a/src/main/java/useless/terrainapi/generation/overworld/MapGenCavesAPI.java b/src/main/java/useless/terrainapi/generation/overworld/api/MapGenCavesAPI.java similarity index 99% rename from src/main/java/useless/terrainapi/generation/overworld/MapGenCavesAPI.java rename to src/main/java/useless/terrainapi/generation/overworld/api/MapGenCavesAPI.java index 8e170d7..acb845e 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/MapGenCavesAPI.java +++ b/src/main/java/useless/terrainapi/generation/overworld/api/MapGenCavesAPI.java @@ -1,4 +1,4 @@ -package useless.terrainapi.generation.overworld; +package useless.terrainapi.generation.overworld.api; import net.minecraft.core.block.Block; import net.minecraft.core.block.tag.BlockTags; diff --git a/src/main/java/useless/terrainapi/mixin/WorldTypeOverworldMixin.java b/src/main/java/useless/terrainapi/mixin/WorldTypeOverworldMixin.java index d3c3889..a84b0bd 100644 --- a/src/main/java/useless/terrainapi/mixin/WorldTypeOverworldMixin.java +++ b/src/main/java/useless/terrainapi/mixin/WorldTypeOverworldMixin.java @@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import useless.terrainapi.generation.overworld.ChunkGeneratorOverworldAPI; +import useless.terrainapi.generation.overworld.api.ChunkGeneratorOverworldAPI; @Mixin(value = WorldTypeOverworld.class, remap = false, priority = 999) public class WorldTypeOverworldMixin { diff --git a/src/main/java/useless/terrainapi/util/Utilities.java b/src/main/java/useless/terrainapi/util/Utilities.java new file mode 100644 index 0000000..21e13ce --- /dev/null +++ b/src/main/java/useless/terrainapi/util/Utilities.java @@ -0,0 +1,23 @@ +package useless.terrainapi.util; + +import net.minecraft.core.data.registry.Registries; +import net.minecraft.core.world.biome.Biome; + +public class Utilities { + public static boolean checkForBiomeInBiomes(Biome biome, String[] biomesKeys){ + for (String key: biomesKeys) { + if (biome.equals(Registries.BIOMES.getItem(key))){ + return true; + } + } + return false; + } + public static boolean checkForBiomeInBiomes(Biome biome, Biome[] biomes){ + for (Biome checkBiome: biomes) { + if (biome.equals(checkBiome)){ + return true; + } + } + return false; + } +} From ceb232f34242a004b743092c5f624aded191d8da Mon Sep 17 00:00:00 2001 From: UselessBullets <80850784+UselessBullets@users.noreply.github.com> Date: Thu, 9 Nov 2023 15:41:23 -0600 Subject: [PATCH 02/13] Refactor --- src/main/java/useless/terrainapi/TerrainInitialization.java | 6 ++++-- src/main/java/useless/terrainapi/config/APIConfig.java | 1 + src/main/java/useless/terrainapi/config/NetherConfig.java | 4 ---- .../useless/terrainapi/generation/nether/NetherConfig.java | 6 ++++++ .../generation/nether/api/ChunkDecoratorNetherAPI.java | 2 +- .../{config => generation/overworld}/OverworldConfig.java | 5 +++-- .../terrainapi/generation/overworld/OverworldFunctions.java | 2 -- .../overworld/api/ChunkDecoratorOverworldAPI.java | 2 +- 8 files changed, 16 insertions(+), 12 deletions(-) delete mode 100644 src/main/java/useless/terrainapi/config/NetherConfig.java create mode 100644 src/main/java/useless/terrainapi/generation/nether/NetherConfig.java rename src/main/java/useless/terrainapi/{config => generation/overworld}/OverworldConfig.java (96%) diff --git a/src/main/java/useless/terrainapi/TerrainInitialization.java b/src/main/java/useless/terrainapi/TerrainInitialization.java index 5a523f4..bb8f899 100644 --- a/src/main/java/useless/terrainapi/TerrainInitialization.java +++ b/src/main/java/useless/terrainapi/TerrainInitialization.java @@ -5,14 +5,16 @@ import net.minecraft.core.world.biome.Biomes; import net.minecraft.core.world.generate.feature.*; import useless.terrainapi.api.TerrainAPI; -import useless.terrainapi.config.NetherConfig; -import useless.terrainapi.config.OverworldConfig; +import useless.terrainapi.generation.nether.NetherConfig; +import useless.terrainapi.generation.overworld.OverworldConfig; import useless.terrainapi.generation.Parameters; import useless.terrainapi.generation.nether.NetherFunctions; import useless.terrainapi.generation.nether.api.ChunkDecoratorNetherAPI; import useless.terrainapi.generation.overworld.OverworldFunctions; import useless.terrainapi.generation.overworld.api.ChunkDecoratorOverworldAPI; +import java.util.HashMap; + public class TerrainInitialization implements TerrainAPI { private static boolean hasInitialized = false; private static final OverworldConfig overworldConfig = ChunkDecoratorOverworldAPI.overworldConfig; diff --git a/src/main/java/useless/terrainapi/config/APIConfig.java b/src/main/java/useless/terrainapi/config/APIConfig.java index 0dd13c5..28f5844 100644 --- a/src/main/java/useless/terrainapi/config/APIConfig.java +++ b/src/main/java/useless/terrainapi/config/APIConfig.java @@ -2,6 +2,7 @@ import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; + public class APIConfig { @SerializedName(value = "Override Default Values") @Expose private boolean configOverride = false; diff --git a/src/main/java/useless/terrainapi/config/NetherConfig.java b/src/main/java/useless/terrainapi/config/NetherConfig.java deleted file mode 100644 index d273042..0000000 --- a/src/main/java/useless/terrainapi/config/NetherConfig.java +++ /dev/null @@ -1,4 +0,0 @@ -package useless.terrainapi.config; - -public class NetherConfig extends OreConfig{ -} diff --git a/src/main/java/useless/terrainapi/generation/nether/NetherConfig.java b/src/main/java/useless/terrainapi/generation/nether/NetherConfig.java new file mode 100644 index 0000000..1666594 --- /dev/null +++ b/src/main/java/useless/terrainapi/generation/nether/NetherConfig.java @@ -0,0 +1,6 @@ +package useless.terrainapi.generation.nether; + +import useless.terrainapi.config.OreConfig; + +public class NetherConfig extends OreConfig { +} diff --git a/src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java b/src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java index dbe2972..14dd05c 100644 --- a/src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java +++ b/src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java @@ -6,7 +6,7 @@ import net.minecraft.core.world.chunk.Chunk; import net.minecraft.core.world.generate.feature.WorldFeature; import useless.terrainapi.config.ConfigManager; -import useless.terrainapi.config.NetherConfig; +import useless.terrainapi.generation.nether.NetherConfig; import useless.terrainapi.generation.ChunkDecoratorAPI; import useless.terrainapi.generation.Parameters; import useless.terrainapi.generation.StructureFeatures; diff --git a/src/main/java/useless/terrainapi/config/OverworldConfig.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldConfig.java similarity index 96% rename from src/main/java/useless/terrainapi/config/OverworldConfig.java rename to src/main/java/useless/terrainapi/generation/overworld/OverworldConfig.java index 195d869..9e76b33 100644 --- a/src/main/java/useless/terrainapi/config/OverworldConfig.java +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldConfig.java @@ -1,14 +1,15 @@ -package useless.terrainapi.config; +package useless.terrainapi.generation.overworld; import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; import net.minecraft.core.block.Block; import net.minecraft.core.data.registry.Registries; import net.minecraft.core.world.biome.Biome; +import useless.terrainapi.config.OreConfig; import java.util.HashMap; -public class OverworldConfig extends OreConfig{ +public class OverworldConfig extends OreConfig { @Expose @SerializedName(value = "Biome Random Grass Block") public HashMap biomeRandomGrassBlock = new HashMap<>(); @Expose @SerializedName(value = "Grass Density") diff --git a/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java index 12ff478..1e65137 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java @@ -2,12 +2,10 @@ import net.minecraft.core.block.Block; import net.minecraft.core.world.biome.Biome; -import net.minecraft.core.world.chunk.Chunk; import net.minecraft.core.world.generate.feature.WorldFeature; import net.minecraft.core.world.generate.feature.WorldFeatureDungeon; import net.minecraft.core.world.generate.feature.WorldFeatureLabyrinth; import net.minecraft.core.world.generate.feature.WorldFeatureTallGrass; -import useless.terrainapi.config.OverworldConfig; import useless.terrainapi.generation.Parameters; import useless.terrainapi.generation.overworld.api.ChunkDecoratorOverworldAPI; import useless.terrainapi.util.Utilities; diff --git a/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java b/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java index 6eef8eb..d592259 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java +++ b/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java @@ -12,7 +12,7 @@ import net.minecraft.core.world.generate.feature.WorldFeatureLiquid; import net.minecraft.core.world.noise.PerlinNoise; import useless.terrainapi.config.ConfigManager; -import useless.terrainapi.config.OverworldConfig; +import useless.terrainapi.generation.overworld.OverworldConfig; import useless.terrainapi.generation.ChunkDecoratorAPI; import useless.terrainapi.generation.Parameters; import useless.terrainapi.generation.StructureFeatures; From c404ad6e0b157f5f2c69c91699551d5ba0da12db Mon Sep 17 00:00:00 2001 From: UselessBullets <80850784+UselessBullets@users.noreply.github.com> Date: Thu, 9 Nov 2023 23:28:13 -0600 Subject: [PATCH 03/13] Javadocs (#9) * Config Manager Docs * OreConfig doc * Changed structure return to Void * Structure Features javadoc * Utilities Docs * GeneratorFeatures Doc * Random Features doc * Ore Features Doc * Update OverworldOreFeatures.java * Nullability Annotations * Overworld function Docs * OverworldConfig Docs * renamed addComplexFeature to addFeature * Overworld Biome Features Doc * Lake Density Config * Additional Internal Tags --- .../terrainapi/TerrainInitialization.java | 14 ++- .../java/useless/terrainapi/TerrainMain.java | 2 + .../terrainapi/config/ConfigManager.java | 21 +++- .../useless/terrainapi/config/OreConfig.java | 15 +++ .../generation/ChunkDecoratorAPI.java | 12 ++- .../generation/GeneratorFeatures.java | 10 +- .../terrainapi/generation/Parameters.java | 16 +--- .../generation/StructureFeatures.java | 25 +++-- .../generation/nether/NetherFunctions.java | 4 + .../nether/api/ChunkDecoratorNetherAPI.java | 10 +- .../overworld/OverworldBiomeFeatures.java | 28 ++++-- .../generation/overworld/OverworldConfig.java | 95 ++++++++++++++++++- .../overworld/OverworldFunctions.java | 50 +++++++++- .../overworld/OverworldOreFeatures.java | 42 ++++++-- .../overworld/OverworldRandomFeatures.java | 35 +++++-- .../api/ChunkDecoratorOverworldAPI.java | 25 +++-- .../useless/terrainapi/util/Utilities.java | 32 +++++++ 17 files changed, 361 insertions(+), 75 deletions(-) diff --git a/src/main/java/useless/terrainapi/TerrainInitialization.java b/src/main/java/useless/terrainapi/TerrainInitialization.java index bb8f899..732a537 100644 --- a/src/main/java/useless/terrainapi/TerrainInitialization.java +++ b/src/main/java/useless/terrainapi/TerrainInitialization.java @@ -13,8 +13,6 @@ import useless.terrainapi.generation.overworld.OverworldFunctions; import useless.terrainapi.generation.overworld.api.ChunkDecoratorOverworldAPI; -import java.util.HashMap; - public class TerrainInitialization implements TerrainAPI { private static boolean hasInitialized = false; private static final OverworldConfig overworldConfig = ChunkDecoratorOverworldAPI.overworldConfig; @@ -108,11 +106,11 @@ public static void initializeOverworldRandom(){ } public static void initializeOverworldBiome(){ ChunkDecoratorOverworldAPI.biomeFeatures.addFeatureSurface(new WorldFeatureRichScorchedDirt(10), 1, new Biome[]{Biomes.OVERWORLD_OUTBACK, Biomes.OVERWORLD_OUTBACK_GRASSY}); - ChunkDecoratorOverworldAPI.biomeFeatures.addComplexFeature(OverworldFunctions::getTreeFeature, null, OverworldFunctions::getTreeDensity, null, -1f); + ChunkDecoratorOverworldAPI.biomeFeatures.addFeature(OverworldFunctions::getTreeFeature, null, OverworldFunctions::getTreeDensity, null, -1f); ChunkDecoratorOverworldAPI.biomeFeatures.addFeatureSurface(new WorldFeatureSugarCaneTall(), 1, new Biome[]{Biomes.OVERWORLD_RAINFOREST}); - ChunkDecoratorOverworldAPI.biomeFeatures.addComplexFeature(OverworldFunctions::flowerTypeCondition, null, (Parameters x) -> ChunkDecoratorOverworldAPI.overworldConfig.getFlowerDensity(x.biome, 0), null, 1f); - ChunkDecoratorOverworldAPI.biomeFeatures.addComplexFeature((Parameters x) -> new WorldFeatureFlowers(Block.flowerYellow.id), null, (Parameters x) -> ChunkDecoratorOverworldAPI.overworldConfig.getYellowFlowerDensity(x.biome, 0), null, 1); - ChunkDecoratorOverworldAPI.biomeFeatures.addComplexFeature(OverworldFunctions::grassTypeCondition, null, (Parameters x) -> ChunkDecoratorOverworldAPI.overworldConfig.getGrassDensity(x.biome, 0), null, 1); + ChunkDecoratorOverworldAPI.biomeFeatures.addFeature(OverworldFunctions::flowerTypeCondition, null, (Parameters x) -> ChunkDecoratorOverworldAPI.overworldConfig.getFlowerDensity(x.biome, 0), null, 1f); + ChunkDecoratorOverworldAPI.biomeFeatures.addFeature((Parameters x) -> new WorldFeatureFlowers(Block.flowerYellow.id), null, (Parameters x) -> ChunkDecoratorOverworldAPI.overworldConfig.getYellowFlowerDensity(x.biome, 0), null, 1); + ChunkDecoratorOverworldAPI.biomeFeatures.addFeature(OverworldFunctions::grassTypeCondition, null, (Parameters x) -> ChunkDecoratorOverworldAPI.overworldConfig.getGrassDensity(x.biome, 0), null, 1); ChunkDecoratorOverworldAPI.biomeFeatures.addFeature(new WorldFeatureSpinifexPatch(), 1, 4, new Biome[]{Biomes.OVERWORLD_OUTBACK}); ChunkDecoratorOverworldAPI.biomeFeatures.addFeature(new WorldFeatureDeadBush(Block.deadbush.id), 1, 2, new Biome[]{Biomes.OVERWORLD_DESERT}); ChunkDecoratorOverworldAPI.biomeFeatures.addFeature(new WorldFeatureCactus(), 1, 10, new Biome[]{Biomes.OVERWORLD_DESERT}); @@ -120,8 +118,8 @@ public static void initializeOverworldBiome(){ public static void initializeNether(){ ChunkDecoratorNetherAPI.oreFeatures.addFeature(new WorldFeatureNetherLava(Block.fluidLavaFlowing.id), 8,120/128f); ChunkDecoratorNetherAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.oreNethercoalNetherrack, 12, 10, 120/128f, false); - ChunkDecoratorNetherAPI.oreFeatures.addComplexFeature((Parameters x) -> new WorldFeatureFire(), null, NetherFunctions::netherFireDensity, null, 120/128f); - ChunkDecoratorNetherAPI.oreFeatures.addComplexFeature((Parameters x) -> new WorldFeatureGlowstoneA(), null, NetherFunctions::netherFireDensity, null, 120/128f); + ChunkDecoratorNetherAPI.oreFeatures.addFeature((Parameters x) -> new WorldFeatureFire(), null, NetherFunctions::netherFireDensity, null, 120/128f); + ChunkDecoratorNetherAPI.oreFeatures.addFeature((Parameters x) -> new WorldFeatureGlowstoneA(), null, NetherFunctions::netherFireDensity, null, 120/128f); ChunkDecoratorNetherAPI.oreFeatures.addFeature(new WorldFeatureGlowstoneB(), 10, 120/128f); ChunkDecoratorNetherAPI.randomFeatures.addFeature(new WorldFeatureLake(Block.fluidLavaStill.id), 8, 120/128f); } diff --git a/src/main/java/useless/terrainapi/TerrainMain.java b/src/main/java/useless/terrainapi/TerrainMain.java index d251712..fec1d59 100644 --- a/src/main/java/useless/terrainapi/TerrainMain.java +++ b/src/main/java/useless/terrainapi/TerrainMain.java @@ -5,6 +5,7 @@ import com.google.gson.GsonBuilder; import net.fabricmc.api.ModInitializer; import net.fabricmc.loader.api.FabricLoader; +import org.jetbrains.annotations.ApiStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import useless.terrainapi.api.TerrainAPI; @@ -19,6 +20,7 @@ public class TerrainMain implements ModInitializer { public void onInitialize() { LOGGER.info("TerrainMain initialized."); } + @ApiStatus.Internal public static void loadModules(){ new TerrainInitialization().onInitialize(); FabricLoader.getInstance().getEntrypoints("terrain-api", TerrainAPI.class).forEach(api -> { diff --git a/src/main/java/useless/terrainapi/config/ConfigManager.java b/src/main/java/useless/terrainapi/config/ConfigManager.java index 096c934..882520d 100644 --- a/src/main/java/useless/terrainapi/config/ConfigManager.java +++ b/src/main/java/useless/terrainapi/config/ConfigManager.java @@ -2,6 +2,7 @@ import net.fabricmc.loader.api.FabricLoader; +import org.jetbrains.annotations.ApiStatus; import useless.terrainapi.TerrainMain; import java.io.*; @@ -15,6 +16,9 @@ public class ConfigManager { private static final HashMap fileHashMap = new HashMap<>(); private static final HashMap configHashMap = new HashMap<>(); + /**Prepares the config file for either saving or loading + * @param id Config Config entry identifier + */ private static void prepareBiomeConfigFile(String id) { if (fileHashMap.get(id) != null) { return; @@ -44,7 +48,11 @@ private static void load(String id, Class clazz) { e.printStackTrace(); } } - public static void save(String id) { + + /**Saves the specified config entry + * @param id Config entry identifier + */ + private static void save(String id) { prepareBiomeConfigFile(id); String jsonString = TerrainMain.GSON.toJson(configHashMap.get(id)); @@ -56,11 +64,22 @@ public static void save(String id) { e.printStackTrace(); } } + + /** + * Saves every config entry + */ + @ApiStatus.Internal public static void saveAll(){ for (String id: configHashMap.keySet()) { save(id); } } + + /** + * @param id Config entry identifier + * @param classOfT Class of the Config entry must extend APIConfig.class + * @return Returns the specified config entry with same type as classOfT + */ public static T getConfig(String id, Class classOfT) { if (configHashMap.get(id) == null){ try { diff --git a/src/main/java/useless/terrainapi/config/OreConfig.java b/src/main/java/useless/terrainapi/config/OreConfig.java index 7d7125b..2e2d4a6 100644 --- a/src/main/java/useless/terrainapi/config/OreConfig.java +++ b/src/main/java/useless/terrainapi/config/OreConfig.java @@ -4,6 +4,7 @@ import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; import net.minecraft.core.block.Block; +import org.jetbrains.annotations.ApiStatus; import useless.terrainapi.TerrainMain; import java.util.HashMap; @@ -15,12 +16,26 @@ public class OreConfig extends APIConfig { public HashMap chancesPerChunk = new HashMap<>(); @SerializedName(value = "Vertical Range") @Expose public HashMap verticalRange = new HashMap<>(); + + /**Creates an ore entry, this can be used directly by OreFeatures#addManagedOreFeature or directly by referencing the HashMaps themselves + * @param block The block to be generated, the block key is used as the key for the hashmap + * @param clusterSize Size in blocks of an ore vein + * @param chances Number of chances per chunk to generate an ore patch, this values scales with world height + * @param range Value from [0, 1], it's the fraction from the bottom of the world to the surface that the ore can generate + */ public void setOreValues(String modID, Block block, int clusterSize, int chances, float range){ if (this.clusterSize.get(block.getKey()) != null){ TerrainMain.LOGGER.warn(modID + String.format(" has changed block %s to generate %d blocks with %d chances and a range of %f", block.getKey(), clusterSize, chances, range)); } setOreValues(block, clusterSize, chances, range); } + /**Creates an ore entry, this can be used directly by OreFeatures#addManagedOreFeature or directly by referencing the HashMaps themselves + * @param block The block to be generated, the block key is used as the key for the hashmap + * @param clusterSize Size in blocks of an ore vein + * @param chances Number of chances per chunk to generate an ore patch, this values scales with world height + * @param range Value from [0, 1], it's the fraction from the bottom of the world to the surface that the ore can generate + */ + @ApiStatus.Internal protected void setOreValues(Block block, int clusterSize, int chances, float range){ if (this.clusterSize.containsKey(block.getKey()) && this.getConfigOverride()){ return; diff --git a/src/main/java/useless/terrainapi/generation/ChunkDecoratorAPI.java b/src/main/java/useless/terrainapi/generation/ChunkDecoratorAPI.java index 3e7c2fb..84d87f1 100644 --- a/src/main/java/useless/terrainapi/generation/ChunkDecoratorAPI.java +++ b/src/main/java/useless/terrainapi/generation/ChunkDecoratorAPI.java @@ -7,6 +7,7 @@ import net.minecraft.core.world.generate.chunk.ChunkDecorator; import net.minecraft.core.world.generate.feature.*; import net.minecraft.core.world.type.WorldTypes; +import org.jetbrains.annotations.ApiStatus; import java.util.Random; @@ -25,14 +26,21 @@ protected ChunkDecoratorAPI(World world) { this.oreHeightModifier = (float)rangeY / 128.0f; } @Override + @ApiStatus.Internal public abstract void decorate(Chunk chunk); + @ApiStatus.Internal public abstract void generateStructures(Biome biome, Chunk chunk, Random random); + @ApiStatus.Internal public abstract void generateOreFeatures(Biome biome, int x, int z, Random random, Chunk chunk); + @ApiStatus.Internal public abstract void generateRandomFeatures(Biome biome, int x, int z, Random random, Chunk chunk); + @ApiStatus.Internal public abstract void generateBiomeFeature(Biome biome, int x, int z, Random random, Chunk chunk); + @ApiStatus.Internal public void generateWithChancesUnderground(WorldFeature worldFeature, float chances, int rangeY, int x, int z, Random random){ generateWithChancesUnderground(worldFeature, chances, rangeY, x, z, 0, 0, random); } + @ApiStatus.Internal public void generateWithChancesUnderground(WorldFeature worldFeature, float chances, int rangeY, int x, int z, int xOff, int zOff, Random random){ for (int i = 0; i < chances; i++) { int posX = x + random.nextInt(16) + xOff; @@ -41,9 +49,11 @@ public void generateWithChancesUnderground(WorldFeature worldFeature, float chan worldFeature.generate(world, random, posX, posY, posZ); } } + @ApiStatus.Internal public void generateWithChancesSurface(WorldFeature worldFeature, float chances, int x, int z, Random random){ generateWithChancesSurface(worldFeature, chances, x, z, 0, 0, random); } + @ApiStatus.Internal public void generateWithChancesSurface(WorldFeature worldFeature, float chances, int x, int z, int xOff, int zOff, Random random){ for (int i = 0; i < chances; i++) { int posX = x + random.nextInt(16) + xOff; @@ -52,7 +62,7 @@ public void generateWithChancesSurface(WorldFeature worldFeature, float chances, worldFeature.generate(world, random, posX, posY, posZ); } } - + @ApiStatus.Internal public void freezeSurface(int x, int z){ int oceanY = this.world.getWorldType().getOceanY(); for (int dx = x + 8; dx < x + 8 + 16; ++dx) { diff --git a/src/main/java/useless/terrainapi/generation/GeneratorFeatures.java b/src/main/java/useless/terrainapi/generation/GeneratorFeatures.java index e1b3e7e..3175e92 100644 --- a/src/main/java/useless/terrainapi/generation/GeneratorFeatures.java +++ b/src/main/java/useless/terrainapi/generation/GeneratorFeatures.java @@ -12,11 +12,13 @@ public class GeneratorFeatures { public List> densityFunctionsList = new ArrayList<>(); public List densityParametersList = new ArrayList<>(); - /** The Object[] are the parameters passed into the provided function, index 0 will always be populated by Biome, index 1 with Random, index 2 with Chunk, index 3 with the ChunkDecorator, and index 4 with the oreHeightModifier. Additional parameters can be added in the method. - * Range Modifier of -1 indicates that the feature should only generate on the surface - * + /**Adds a world feature entry + * @param featureFunction Function that takes a Parameters object and returns a WorldFeature + * @param featureParameters Object[] of additional parameters that will be included with the Parameters object passed into the feature function + * @param densityFunction Function that takes a Parameters object and returns an Integer representing the number of attempts per chunk + * @param densityParameters Object[] of additional parameters that will be included with the Parameters object passed into the density function */ - public void addComplexFeature(Function featureFunction, Object[] featureParameters, Function densityFunction, Object[] densityParameters){ + public void addFeature(Function featureFunction, Object[] featureParameters, Function densityFunction, Object[] densityParameters){ featureFunctionsList.add(featureFunction); featureParametersList.add(featureParameters); densityFunctionsList.add(densityFunction); diff --git a/src/main/java/useless/terrainapi/generation/Parameters.java b/src/main/java/useless/terrainapi/generation/Parameters.java index 00103d1..594f198 100644 --- a/src/main/java/useless/terrainapi/generation/Parameters.java +++ b/src/main/java/useless/terrainapi/generation/Parameters.java @@ -4,9 +4,11 @@ import net.minecraft.core.world.chunk.Chunk; import net.minecraft.core.world.generate.chunk.ChunkDecorator; -import java.lang.reflect.Array; import java.util.Random; +/** + * Container for references to chunk decorator info + */ public class Parameters { public Biome biome; public Random random; @@ -27,16 +29,4 @@ public Parameters(Parameters baseParameter, Object[] customParameters){ this(baseParameter.biome, baseParameter.random, baseParameter.chunk, baseParameter.decorator); this.customParameters = customParameters; } - - public static T[] concatenate(T[] a, T[] b) { - int aLen = a.length; - int bLen = b.length; - - @SuppressWarnings("unchecked") - T[] c = (T[]) Array.newInstance(a.getClass().getComponentType(), aLen + bLen); - System.arraycopy(a, 0, c, 0, aLen); - System.arraycopy(b, 0, c, aLen, bLen); - - return c; - } } diff --git a/src/main/java/useless/terrainapi/generation/StructureFeatures.java b/src/main/java/useless/terrainapi/generation/StructureFeatures.java index d9bddf6..2e5c84c 100644 --- a/src/main/java/useless/terrainapi/generation/StructureFeatures.java +++ b/src/main/java/useless/terrainapi/generation/StructureFeatures.java @@ -1,19 +1,28 @@ package useless.terrainapi.generation; +import net.minecraft.core.world.generate.feature.WorldFeature; + import java.util.ArrayList; import java.util.List; import java.util.function.Function; public class StructureFeatures extends GeneratorFeatures{ - public List> featureFunctionsList = new ArrayList<>(); + public List> featureFunctionList = new ArrayList<>(); public List featureParametersList = new ArrayList<>(); - /** The Object[] are the parameters passed into the provided function, index 0 will always be populated by Biome, index 1 with Random, index 2 with Chunk, index 3 with the ChunkDecorator, and index 4 with the oreHeightModifier. Additional parameters can be added in the method. - * Range Modifier of -1 indicates that the feature should only generate on the surface - * + + /**Adds a structure entry + * @param function Function that takes a Parameters object and handles the generation + * @param additionalParameters Object[] of additional parameters that will be included with the Parameters object passed into the function + */ + public void addStructure(Function function, Object[] additionalParameters){ + featureFunctionList.add(function); + featureParametersList.add(additionalParameters); + assert featureFunctionList.size() == featureParametersList.size(): "Structure Features list sizes do not match!!"; + } + + /** Do not use this method, use addStructure instead */ - public void addStructure(Function function, Object[] functionParameters){ - featureFunctionsList.add(function); - featureParametersList.add(functionParameters); - assert featureFunctionsList.size() == featureParametersList.size(): "Structure Features list sizes do not match!!"; + public void addFeature(Function featureFunction, Object[] featureParameters, Function densityFunction, Object[] densityParameters){ + throw new RuntimeException("Illegal use of method \"addFeature\" inside StructureFeatures"); } } diff --git a/src/main/java/useless/terrainapi/generation/nether/NetherFunctions.java b/src/main/java/useless/terrainapi/generation/nether/NetherFunctions.java index bca8480..075dffb 100644 --- a/src/main/java/useless/terrainapi/generation/nether/NetherFunctions.java +++ b/src/main/java/useless/terrainapi/generation/nether/NetherFunctions.java @@ -3,6 +3,10 @@ import useless.terrainapi.generation.Parameters; public class NetherFunctions { + /**Vanilla Nether fire density + * @param parameters Parameters Container + * @return Amount of fire per chunk + */ public static int netherFireDensity(Parameters parameters){ return parameters.random.nextInt(parameters.random.nextInt(10) + 1); } diff --git a/src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java b/src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java index 14dd05c..127e597 100644 --- a/src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java +++ b/src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java @@ -5,6 +5,7 @@ import net.minecraft.core.world.biome.Biome; import net.minecraft.core.world.chunk.Chunk; import net.minecraft.core.world.generate.feature.WorldFeature; +import org.jetbrains.annotations.ApiStatus; import useless.terrainapi.config.ConfigManager; import useless.terrainapi.generation.nether.NetherConfig; import useless.terrainapi.generation.ChunkDecoratorAPI; @@ -28,6 +29,7 @@ protected ChunkDecoratorNetherAPI(World world) { } @Override + @ApiStatus.Internal public void decorate(Chunk chunk) { int chunkX = chunk.xPosition; int chunkZ = chunk.zPosition; @@ -50,13 +52,15 @@ public void decorate(Chunk chunk) { BlockSand.fallInstantly = false; } + @ApiStatus.Internal public void generateStructures(Biome biome, Chunk chunk, Random random){ - int featureSize = structureFeatures.featureFunctionsList.size(); + int featureSize = structureFeatures.featureFunctionList.size(); for (int i = 0; i < featureSize; i++) { - structureFeatures.featureFunctionsList.get(i) + structureFeatures.featureFunctionList.get(i) .apply(new Parameters(parameterBase, structureFeatures.featureParametersList.get(i))); } } + @ApiStatus.Internal public void generateOreFeatures(Biome biome, int x, int z, Random random, Chunk chunk){ int featureSize = oreFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { @@ -70,6 +74,7 @@ public void generateOreFeatures(Biome biome, int x, int z, Random random, Chunk generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, random); } } + @ApiStatus.Internal public void generateRandomFeatures(Biome biome, int x, int z, Random random, Chunk chunk){ int featureSize = randomFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { @@ -88,6 +93,7 @@ public void generateRandomFeatures(Biome biome, int x, int z, Random random, Chu } } } + @ApiStatus.Internal public void generateBiomeFeature(Biome biome, int x, int z, Random random, Chunk chunk){ int featureSize = biomeFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { diff --git a/src/main/java/useless/terrainapi/generation/overworld/OverworldBiomeFeatures.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldBiomeFeatures.java index 693053c..4e41b33 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/OverworldBiomeFeatures.java +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldBiomeFeatures.java @@ -11,19 +11,35 @@ public class OverworldBiomeFeatures extends GeneratorFeatures { public List rangeModifierList = new ArrayList<>(); + + /**Adds a world feature entry + * @param feature WorldFeature to generate + * @param chances Number of attempts per chunk + * @param biomes List of biomes to generate in, generates in any biome if array is null + */ public void addFeatureSurface(WorldFeature feature, int chances, Biome[] biomes){ addFeature(feature, -1f, chances, biomes); } + + /**Adds a world feature entry + * @param feature WorldFeature to generate + * @param chances Number of attempts per chunk + * @param rangeModifier Fraction of the world from the bottom to the surface to generate inside, a value of -1 indicates to spawn on the surface only + * @param biomes List of biomes to generate in, generates in any biome if array is null + */ public void addFeature(WorldFeature feature, float rangeModifier, int chances, Biome[] biomes){ - addComplexFeature((Parameters x) -> feature, null, OverworldFunctions::getStandardBiomesDensity, new Object[]{chances, biomes}, rangeModifier); + addFeature((Parameters x) -> feature, null, OverworldFunctions::getStandardBiomesDensity, new Object[]{chances, biomes}, rangeModifier); } - /** The Object[] are the parameters passed into the provided function, index 0 will always be populated by Biome, index 1 with Random, index 2 with Chunk, and index 3 with the ChunkDecorator. Additional parameters can be added in the method. - * Range Modifier of -1 indicates that the feature should only generate on the surface - * + /**Adds a world feature entry + * @param featureFunction Function that takes a Parameters object and returns a WorldFeature + * @param featureParameters Object[] of additional parameters that will be included with the Parameters object passed into the feature function + * @param densityFunction Function that takes a Parameters object and returns an Integer representing the number of attempts per chunk + * @param densityParameters Object[] of additional parameters that will be included with the Parameters object passed into the density function + * @param rangeModifier Fraction of the world from the bottom to the surface to generate inside, a value of -1 indicates to spawn on the surface only */ - public void addComplexFeature(Function featureFunction, Object[] featureParameters, Function densityFunction, Object[] densityParameters, float rangeModifier){ - super.addComplexFeature(featureFunction, featureParameters, densityFunction, densityParameters); + public void addFeature(Function featureFunction, Object[] featureParameters, Function densityFunction, Object[] densityParameters, float rangeModifier){ + super.addFeature(featureFunction, featureParameters, densityFunction, densityParameters); rangeModifierList.add(rangeModifier); } } diff --git a/src/main/java/useless/terrainapi/generation/overworld/OverworldConfig.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldConfig.java index 9e76b33..c13ad77 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/OverworldConfig.java +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldConfig.java @@ -5,8 +5,10 @@ import net.minecraft.core.block.Block; import net.minecraft.core.data.registry.Registries; import net.minecraft.core.world.biome.Biome; +import org.jetbrains.annotations.NotNull; import useless.terrainapi.config.OreConfig; +import javax.annotation.Nullable; import java.util.HashMap; public class OverworldConfig extends OreConfig { @@ -20,15 +22,31 @@ public class OverworldConfig extends OreConfig { public HashMap yellowFlowerDensityMap = new HashMap<>(); @Expose @SerializedName(value = "Tree Density") public HashMap treeDensityMap = new HashMap<>(); + @Expose @SerializedName(value = "Lake Density") + public HashMap lakeDensityMap = new HashMap<>(); + public int defaultLakeDensity = 4; + + /**Specifies the block to randomly replace some grass with in the specified biome + */ public void addRandomGrassBlock(Biome biome, Block block) { if (getConfigOverride() && getRandomGrassBlock(biome) != null){ return; } biomeRandomGrassBlock.put(Registries.BIOMES.getKey(biome), block.getKey()); } + + /** + * @return Biome's random grass block, returns null if there is no entry for the biome + */ + @Nullable public Block getRandomGrassBlock(Biome biome){ return Block.getBlockByName(biomeRandomGrassBlock.get(Registries.BIOMES.getKey(biome))); } + + /** + * @return Biome's random grass block, returns defaultValue if there is no entry for the biome + */ + @NotNull public Block getRandomGrassBlock(Biome biome, Block defaultValue){ Block returnBlock = Block.getBlockByName(biomeRandomGrassBlock.get(Registries.BIOMES.getKey(biome))); if (returnBlock == null){ @@ -36,54 +54,129 @@ public Block getRandomGrassBlock(Biome biome, Block defaultValue){ } return returnBlock; } + + /**Specifies the number of chances for grass to spawn for the specified biome + */ public void addGrassDensity(Biome biome, int density){ if (getConfigOverride() && getGrassDensity(biome) != null){ return; } grassDensityMap.put(Registries.BIOMES.getKey(biome), density); } + + /** + * @return Biome's grass density, returns null if there is no entry for the biome + */ + @Nullable public Integer getGrassDensity(Biome biome){ return grassDensityMap.get(Registries.BIOMES.getKey(biome)); } + + /** + * @return Biome's grass density, returns defaultValue if there is no entry for the biome + */ + @NotNull public Integer getGrassDensity(Biome biome, int defaultValue){ return grassDensityMap.getOrDefault(Registries.BIOMES.getKey(biome), defaultValue); } + /**Specifies the number of chances for red/yellow flowers patches to spawn for the specified biome + */ public void addFlowerDensity(Biome biome, int density){ if (getConfigOverride() && getFlowerDensity(biome) != null){ return; } flowerDensityMap.put(Registries.BIOMES.getKey(biome), density); } + + /** + * @return Biome's red/yellow density, returns null if there is no entry for the biome + */ + @Nullable public Integer getFlowerDensity(Biome biome){ return flowerDensityMap.get(Registries.BIOMES.getKey(biome)); } + + /** + * @return Biome's red/yellow density, returns defaultValue if there is no entry for the biome + */ + @NotNull public Integer getFlowerDensity(Biome biome, int defaultValue){ return flowerDensityMap.getOrDefault(Registries.BIOMES.getKey(biome), defaultValue); } + /**Specifies the number of chances for yellow flowers to spawn for the specified biome + */ public void addYellowFlowerDensity(Biome biome, int density){ if (getConfigOverride() && getYellowFlowerDensity(biome) != null){ return; } yellowFlowerDensityMap.put(Registries.BIOMES.getKey(biome), density); } + + /** + * @return Biome's yellow flower density, returns null if there is no entry for the biome + */ + @Nullable public Integer getYellowFlowerDensity(Biome biome){ return yellowFlowerDensityMap.get(Registries.BIOMES.getKey(biome)); } + + /** + * @return Biome's yellow flower density, returns defaultValue if there is no entry for the biome + */ + @NotNull public Integer getYellowFlowerDensity(Biome biome, int defaultValue){ return yellowFlowerDensityMap.getOrDefault(Registries.BIOMES.getKey(biome), defaultValue); } + /**Specifies the number of chances for trees to spawn for the specified biome + */ public void addTreeDensity(Biome biome, int density){ if (getConfigOverride() && getTreeDensity(biome) != null){ return; } treeDensityMap.put(Registries.BIOMES.getKey(biome), density); } + + /** + * @return Biome's tree density, returns null if there is no entry for the biome + */ + @Nullable public Integer getTreeDensity(Biome biome){ return treeDensityMap.get(Registries.BIOMES.getKey(biome)); - }public Integer getTreeDensity(Biome biome, int defaultValue){ + } + + /** + * @return Biome's tree density, returns defaultValue if there is no entry for the biome + */ + @NotNull + public Integer getTreeDensity(Biome biome, int defaultValue){ return treeDensityMap.getOrDefault(Registries.BIOMES.getKey(biome), defaultValue); } + + /**Specifies the number of chances for lake to spawn for the specified biome + */ + public void addLakeDensity(Biome biome, int density){ + if (getConfigOverride() && getTreeDensity(biome) != null){ + return; + } + lakeDensityMap.put(Registries.BIOMES.getKey(biome), density); + } + + /** + * @return Biome's lake density, returns null if there is no entry for the biome + */ + @Nullable + public Integer getLakeDensity(Biome biome){ + return lakeDensityMap.get(Registries.BIOMES.getKey(biome)); + } + + /** + * @return Biome's lake density, returns defaultValue if there is no entry for the biome + */ + @NotNull + public Integer getLakeDensity(Biome biome, int defaultValue){ + return lakeDensityMap.getOrDefault(Registries.BIOMES.getKey(biome), defaultValue); + } } diff --git a/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java index 1e65137..6bb85a3 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java @@ -6,6 +6,7 @@ import net.minecraft.core.world.generate.feature.WorldFeatureDungeon; import net.minecraft.core.world.generate.feature.WorldFeatureLabyrinth; import net.minecraft.core.world.generate.feature.WorldFeatureTallGrass; +import org.jetbrains.annotations.Nullable; import useless.terrainapi.generation.Parameters; import useless.terrainapi.generation.overworld.api.ChunkDecoratorOverworldAPI; import useless.terrainapi.util.Utilities; @@ -14,11 +15,21 @@ public class OverworldFunctions { public static OverworldConfig overworldConfig = ChunkDecoratorOverworldAPI.overworldConfig; + + /**Vanilla tree feature generator + * @param parameters Parameters Container + * @return Tree feature as specified by Biome#getRandomWorldGenForTrees + */ public static WorldFeature getTreeFeature(Parameters parameters){ WorldFeature treeFeature = parameters.biome.getRandomWorldGenForTrees(parameters.random); treeFeature.func_517_a(1.0, 1.0, 1.0); return treeFeature; } + + /**Vanilla tree density + * @param parameters Parameters Container + * @return treeDensityOverride if applicable, otherwise returns the biome's tree density from OverworldConfig's tree density hashmap + */ public static int getTreeDensity(Parameters parameters){ ChunkDecoratorOverworldAPI decorator = (ChunkDecoratorOverworldAPI) parameters.decorator; @@ -47,13 +58,21 @@ public static int getTreeDensity(Parameters parameters){ return treeDensity + noiseValue + treeDensityOffset; } } + /**Vanilla grass feature generator + * @param parameters Parameters Container + * @return Randomly returns tall grass or the random grass for the biome as specified in the OverworldConfig biomeRandomGrassBlock hashmap + */ public static WorldFeature grassTypeCondition(Parameters parameters){ Block block = Block.tallgrass; if (Utilities.checkForBiomeInBiomes(parameters.biome, overworldConfig.biomeRandomGrassBlock.keySet().toArray(new String[0])) && parameters.random.nextInt(3) != 0) { - block = overworldConfig.getRandomGrassBlock(parameters.biome); + block = overworldConfig.getRandomGrassBlock(parameters.biome, block); } return new WorldFeatureTallGrass(block.id); } + /**Vanilla flower feature generator + * @param parameters Parameters Container + * @return Randomly returns yellow or red flower features + */ public static WorldFeature flowerTypeCondition(Parameters parameters){ int blockId = Block.flowerYellow.id; if (parameters.random.nextInt(3) != 0) { @@ -61,6 +80,11 @@ public static WorldFeature flowerTypeCondition(Parameters parameters){ } return new WorldFeatureTallGrass(blockId); } + + /**Vanilla biome feature density + * @param parameters Parameters Container + * @return number of chances per chunk if in valid biome + */ public static int getStandardBiomesDensity(Parameters parameters){ int chance = (int) parameters.customParameters[0]; Biome[] biomes = (Biome[]) parameters.customParameters[1]; @@ -70,6 +94,11 @@ public static int getStandardBiomesDensity(Parameters parameters){ } return 0; } + + /**Vanilla ore density + * @param parameters Parameters Container + * @return number of chances per chunk scaled by the oreHeightModifier if in valid biome + */ public static int getStandardOreBiomesDensity(Parameters parameters){ float oreHeightModifier = ((ChunkDecoratorOverworldAPI) parameters.decorator).oreHeightModifier; int chance = (int) parameters.customParameters[0]; @@ -80,7 +109,12 @@ public static int getStandardOreBiomesDensity(Parameters parameters){ } return 0; } - public static Boolean generateDungeons(Parameters parameters){ + /**Vanilla dungeon generation code + * @param parameters Parameters Container + * @return null + */ + @Nullable + public static Void generateDungeons(Parameters parameters){ int x = parameters.chunk.xPosition * 16; int z = parameters.chunk.zPosition * 16; ChunkDecoratorOverworldAPI decoratorOverworldAPI = (ChunkDecoratorOverworldAPI) parameters.decorator; @@ -94,9 +128,15 @@ public static Boolean generateDungeons(Parameters parameters){ new WorldFeatureDungeon(Block.cobbleStone.id, Block.cobbleStoneMossy.id, null).generate(decoratorOverworldAPI.world, parameters.random, xPos, yPos, zPos); } } - return true; + return null; } - public static Boolean generateLabyrinths(Parameters parameters){ + + /**Vanilla labyrinth generation code + * @param parameters Parameters Container + * @return null + */ + @Nullable + public static Void generateLabyrinths(Parameters parameters){ ChunkDecoratorOverworldAPI decorator = (ChunkDecoratorOverworldAPI) parameters.decorator; int x = parameters.chunk.xPosition * 16; int z = parameters.chunk.zPosition * 16; @@ -111,6 +151,6 @@ public static Boolean generateLabyrinths(Parameters parameters){ Random lRand = parameters.chunk.getChunkRandom(75644760L); new WorldFeatureLabyrinth().generate(decorator.world, lRand, xPos, yPos, zPos); } - return true; + return null; } } diff --git a/src/main/java/useless/terrainapi/generation/overworld/OverworldOreFeatures.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldOreFeatures.java index e19a968..0122f50 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/OverworldOreFeatures.java +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldOreFeatures.java @@ -18,24 +18,54 @@ public class OverworldOreFeatures extends GeneratorFeatures { public OverworldOreFeatures(OreConfig config){ this.config = config; } + + /**Adds a world feature entry + * @param feature WorldFeature to generate + * @param chances Number of attempts per chunk + * @param rangeModifier Fraction of the world from the bottom to the surface to generate inside, a value of -1 indicates to spawn on the surface only + */ public void addFeature(WorldFeature feature, int chances, float rangeModifier){ addFeature(feature, chances, rangeModifier, null); } + + /**Adds a world feature entry + * @param feature WorldFeature to generate + * @param chances Number of attempts per chunk + * @param rangeModifier Fraction of the world from the bottom to the surface to generate inside, a value of -1 indicates to spawn on the surface only + * @param biomes List of biomes to generate in, generates in any biome if array is null + */ public void addFeature(WorldFeature feature, int chances, float rangeModifier, Biome[] biomes){ - addComplexFeature((Parameters x) -> feature, null, OverworldFunctions::getStandardOreBiomesDensity, new Object[]{chances, biomes}, rangeModifier); + addFeature((Parameters x) -> feature, null, OverworldFunctions::getStandardOreBiomesDensity, new Object[]{chances, biomes}, rangeModifier); } - /** The Object[] are the parameters passed into the provided function, index 0 will always be populated by Biome, index 1 with Random, index 2 with Chunk, index 3 with the ChunkDecorator, and index 4 with the oreHeightModifier. Additional parameters can be added in the method. - * Range Modifier of -1 indicates that the feature should only generate on the surface - * + + /**Adds a world feature entry + * @param featureFunction Function that takes a Parameters object and returns a WorldFeature + * @param featureParameters Object[] of additional parameters that will be included with the Parameters object passed into the feature function + * @param densityFunction Function that takes a Parameters object and returns an Integer representing the number of attempts per chunk + * @param densityParameters Object[] of additional parameters that will be included with the Parameters object passed into the density function + * @param rangeModifier Fraction of the world from the bottom to the surface to generate inside, a value of -1 indicates to spawn on the surface only */ - public void addComplexFeature(Function featureFunction, Object[] featureParameters, Function densityFunction, Object[] densityParameters, float rangeModifier){ - super.addComplexFeature(featureFunction, featureParameters, densityFunction, densityParameters); + public void addFeature(Function featureFunction, Object[] featureParameters, Function densityFunction, Object[] densityParameters, float rangeModifier){ + super.addFeature(featureFunction, featureParameters, densityFunction, densityParameters); rangeModifierList.add(rangeModifier); } + + /**Adds an WorldFeatureOre, which has its generation characteristics managed by OreConfig + * @param block Ore to generate + * @param defaultClusterSize Default size in blocks of an ore vein + * @param defaultChances Default number of chances per chunk to generate an ore patch, this values scales with world height + * @param defaultRange Value from [0, 1], it's the default fraction from the bottom of the world to the surface that the ore can generate + * @param hasStoneStates Does ore have states for each stone type + */ public void addManagedOreFeature(String modID, Block block, int defaultClusterSize, int defaultChances, float defaultRange, boolean hasStoneStates){ config.setOreValues(modID, block, defaultClusterSize, defaultChances, defaultRange); addManagedOreFeature(block, hasStoneStates); } + + /**Adds an WorldFeatureOre, which has its generation characteristics managed by OreConfig + * @param block Ore to generate + * @param hasStoneStates Does ore have states for each stone type + */ public void addManagedOreFeature(Block block, boolean hasStoneStates){ String currentBlock = block.getKey(); addFeature(new WorldFeatureOre(block.id, config.clusterSize.get(currentBlock), hasStoneStates), config.chancesPerChunk.get(currentBlock), config.verticalRange.get(currentBlock)); diff --git a/src/main/java/useless/terrainapi/generation/overworld/OverworldRandomFeatures.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldRandomFeatures.java index 39e9226..a9b1ae6 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/OverworldRandomFeatures.java +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldRandomFeatures.java @@ -12,21 +12,44 @@ public class OverworldRandomFeatures extends GeneratorFeatures { public List rangeModifierList = new ArrayList<>(); public List inverseProbabilityList = new ArrayList<>(); + /**Adds a world feature entry, will only generate on the surface + * @param feature WorldFeature to generate + * @param inverseProbability Inverse of the probability, example inverseProbability of 2 means a 50% chance + */ public void addFeatureSurface(WorldFeature feature, int inverseProbability){ addFeature(feature, inverseProbability, -1f); } + + /**Adds a world feature entry + * @param feature WorldFeature to generate + * @param inverseProbability Inverse of the probability, example inverseProbability of 2 means a 50% chance + * @param rangeModifier Fraction of the world from the bottom to the surface to generate inside, a value of -1 indicates to spawn on the surface only + */ public void addFeature(WorldFeature feature, int inverseProbability, float rangeModifier){ addFeature(feature, inverseProbability, rangeModifier,1, null); } + + /**Adds a world feature entry + * @param feature WorldFeature to generate + * @param inverseProbability Inverse of the probability, example inverseProbability of 2 means a 50% chance + * @param rangeModifier Fraction of the world from the bottom to the surface to generate inside, a value of -1 indicates to spawn on the surface only + * @param chances Number of attempts per chunk + * @param biomes List of biomes to generate in, generates in any biome if array is null + */ public void addFeature(WorldFeature feature, int inverseProbability, float rangeModifier, int chances, Biome[] biomes){ - addComplexFeature((Parameters x) -> feature, null, OverworldFunctions::getStandardBiomesDensity, new Object[]{chances, biomes}, inverseProbability, rangeModifier); + addFeature((Parameters x) -> feature, null, OverworldFunctions::getStandardBiomesDensity, new Object[]{chances, biomes}, inverseProbability, rangeModifier); } - /** The Object[] are the parameters passed into the provided function, index 0 will always be populated by Biome, index 1 with Random, index 2 with Chunk, and index 3 with the ChunkDecorator. Additional parameters can be added in the method. - * Range Modifier of -1 indicates that the feature should only generate on the surface - * + + /**Adds a world feature entry + * @param featureFunction Function that takes a Parameters object and returns a WorldFeature + * @param featureParameters Object[] of additional parameters that will be included with the Parameters object passed into the feature function + * @param densityFunction Function that takes a Parameters object and returns an Integer representing the number of attempts per chunk + * @param densityParameters Object[] of additional parameters that will be included with the Parameters object passed into the density function + * @param inverseProbability Inverse of the probability, example inverseProbability of 2 means a 50% chance + * @param rangeModifier Fraction of the world from the bottom to the surface to generate inside, a value of -1 indicates to spawn on the surface only */ - public void addComplexFeature(Function featureFunction, Object[] featureParameters, Function densityFunction, Object[] densityParameters, int inverseProbability, float rangeModifier){ - super.addComplexFeature(featureFunction, featureParameters, densityFunction, densityParameters); + public void addFeature(Function featureFunction, Object[] featureParameters, Function densityFunction, Object[] densityParameters, int inverseProbability, float rangeModifier){ + super.addFeature(featureFunction, featureParameters, densityFunction, densityParameters); rangeModifierList.add(rangeModifier); inverseProbabilityList.add(inverseProbability); } diff --git a/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java b/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java index d592259..7684ca8 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java +++ b/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java @@ -11,6 +11,7 @@ import net.minecraft.core.world.generate.feature.WorldFeatureLake; import net.minecraft.core.world.generate.feature.WorldFeatureLiquid; import net.minecraft.core.world.noise.PerlinNoise; +import org.jetbrains.annotations.ApiStatus; import useless.terrainapi.config.ConfigManager; import useless.terrainapi.generation.overworld.OverworldConfig; import useless.terrainapi.generation.ChunkDecoratorAPI; @@ -26,7 +27,6 @@ public class ChunkDecoratorOverworldAPI extends ChunkDecoratorAPI { public static OverworldConfig overworldConfig = ConfigManager.getConfig("overworld", OverworldConfig.class); public final PerlinNoise treeDensityNoise; public final int treeDensityOverride; - private final int lakeDensityDefault = 4; private Parameters parameterBase; public static StructureFeatures structureFeatures = new StructureFeatures(); public static OverworldOreFeatures oreFeatures = new OverworldOreFeatures(overworldConfig); @@ -42,6 +42,7 @@ public ChunkDecoratorOverworldAPI(World world) { this(world, -1); } @Override + @ApiStatus.Internal public void decorate(Chunk chunk) { int chunkX = chunk.xPosition; int chunkZ = chunk.zPosition; @@ -63,11 +64,10 @@ public void decorate(Chunk chunk) { if (biome == Biomes.OVERWORLD_SWAMPLAND){ swampFeature(xCoord, zCoord, swampRand); } - int lakeChance = getLakeChance(biome); parameterBase = new Parameters(biome, random, chunk, this); - generateLakeFeature(lakeChance, xCoord, zCoord, biome, random); + generateLakeFeature(overworldConfig.getLakeDensity(biome, overworldConfig.defaultLakeDensity), xCoord, zCoord, biome, random); generateStructures(biome, chunk, random); generateOreFeatures(biome, xCoord, zCoord, random, chunk); @@ -82,6 +82,7 @@ public void decorate(Chunk chunk) { BlockSand.fallInstantly = false; } + @ApiStatus.Internal public void swampFeature(int x, int z, Random random){ for (int dx = 0; dx < 16; ++dx) { for (int dz = 0; dz < 16; ++dz) { @@ -102,15 +103,7 @@ public void swampFeature(int x, int z, Random random){ } } } - public int getLakeChance(Biome biome){ - if (biome == Biomes.OVERWORLD_SWAMPLAND) { - return 2; - } - if (biome == Biomes.OVERWORLD_DESERT) { - return 0; - } - return lakeDensityDefault; - } + @ApiStatus.Internal public void generateLakeFeature(int lakeChance, int x, int z, Biome biome, Random random){ if (lakeChance != 0 && random.nextInt(lakeChance) == 0) { int fluid = Block.fluidWaterStill.id; @@ -131,13 +124,15 @@ public void generateLakeFeature(int lakeChance, int x, int z, Biome biome, Rando } } } + @ApiStatus.Internal public void generateStructures(Biome biome, Chunk chunk, Random random){ - int featureSize = structureFeatures.featureFunctionsList.size(); + int featureSize = structureFeatures.featureFunctionList.size(); for (int i = 0; i < featureSize; i++) { - structureFeatures.featureFunctionsList.get(i) + structureFeatures.featureFunctionList.get(i) .apply(new Parameters(parameterBase, structureFeatures.featureParametersList.get(i))); } } + @ApiStatus.Internal public void generateOreFeatures(Biome biome, int x, int z, Random random, Chunk chunk){ int featureSize = oreFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { @@ -151,6 +146,7 @@ public void generateOreFeatures(Biome biome, int x, int z, Random random, Chunk generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, random); } } + @ApiStatus.Internal public void generateRandomFeatures(Biome biome, int x, int z, Random random, Chunk chunk){ int featureSize = randomFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { @@ -169,6 +165,7 @@ public void generateRandomFeatures(Biome biome, int x, int z, Random random, Chu } } } + @ApiStatus.Internal public void generateBiomeFeature(Biome biome, int x, int z, Random random, Chunk chunk){ int featureSize = biomeFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { diff --git a/src/main/java/useless/terrainapi/util/Utilities.java b/src/main/java/useless/terrainapi/util/Utilities.java index 21e13ce..28cc746 100644 --- a/src/main/java/useless/terrainapi/util/Utilities.java +++ b/src/main/java/useless/terrainapi/util/Utilities.java @@ -3,7 +3,15 @@ import net.minecraft.core.data.registry.Registries; import net.minecraft.core.world.biome.Biome; +import java.lang.reflect.Array; + public class Utilities { + + /**Check if biome is present in the array of biomes + * @param biome Biome to check + * @param biomesKeys Array of biomes keys + * @return True if biome is in array + */ public static boolean checkForBiomeInBiomes(Biome biome, String[] biomesKeys){ for (String key: biomesKeys) { if (biome.equals(Registries.BIOMES.getItem(key))){ @@ -12,6 +20,12 @@ public static boolean checkForBiomeInBiomes(Biome biome, String[] biomesKeys){ } return false; } + + /**Check if biome is present in the array of biomes + * @param biome Biome to check + * @param biomes Array of biomes + * @return True if biome is in array + */ public static boolean checkForBiomeInBiomes(Biome biome, Biome[] biomes){ for (Biome checkBiome: biomes) { if (biome.equals(checkBiome)){ @@ -20,4 +34,22 @@ public static boolean checkForBiomeInBiomes(Biome biome, Biome[] biomes){ } return false; } + + /**Combines two same type arrays + * @param a Array 1 + * @param b Array 2 + * @param Type of both arrays + * @return Array A + Array B + */ + public static T[] concatenate(T[] a, T[] b) { + int aLen = a.length; + int bLen = b.length; + + @SuppressWarnings("unchecked") + T[] c = (T[]) Array.newInstance(a.getClass().getComponentType(), aLen + bLen); + System.arraycopy(a, 0, c, 0, aLen); + System.arraycopy(b, 0, c, aLen, bLen); + + return c; + } } From 3b306be9c888c2a83845c7d19995a07d96d973fa Mon Sep 17 00:00:00 2001 From: UselessBullets <80850784+UselessBullets@users.noreply.github.com> Date: Thu, 9 Nov 2023 23:31:50 -0600 Subject: [PATCH 04/13] Extra Annotations --- .../terrainapi/TerrainInitialization.java | 8 ++--- .../useless/terrainapi/config/APIConfig.java | 3 ++ .../useless/terrainapi/config/OreConfig.java | 9 +++++ .../generation/ChunkDecoratorAPI.java | 2 +- .../generation/GeneratorFeatures.java | 5 +++ .../generation/StructureFeatures.java | 14 +++++--- .../overworld/OverworldBiomeFeatures.java | 2 ++ .../generation/overworld/OverworldConfig.java | 36 ++++++++++++++++++- .../overworld/OverworldOreFeatures.java | 2 ++ .../overworld/OverworldRandomFeatures.java | 8 +++++ .../useless/terrainapi/util/Utilities.java | 19 ++++++++++ 11 files changed, 96 insertions(+), 12 deletions(-) diff --git a/src/main/java/useless/terrainapi/TerrainInitialization.java b/src/main/java/useless/terrainapi/TerrainInitialization.java index bb8f899..0edce61 100644 --- a/src/main/java/useless/terrainapi/TerrainInitialization.java +++ b/src/main/java/useless/terrainapi/TerrainInitialization.java @@ -5,11 +5,10 @@ import net.minecraft.core.world.biome.Biomes; import net.minecraft.core.world.generate.feature.*; import useless.terrainapi.api.TerrainAPI; -import useless.terrainapi.generation.nether.NetherConfig; -import useless.terrainapi.generation.overworld.OverworldConfig; import useless.terrainapi.generation.Parameters; import useless.terrainapi.generation.nether.NetherFunctions; import useless.terrainapi.generation.nether.api.ChunkDecoratorNetherAPI; +import useless.terrainapi.generation.overworld.OverworldConfig; import useless.terrainapi.generation.overworld.OverworldFunctions; import useless.terrainapi.generation.overworld.api.ChunkDecoratorOverworldAPI; @@ -18,7 +17,6 @@ public class TerrainInitialization implements TerrainAPI { private static boolean hasInitialized = false; private static final OverworldConfig overworldConfig = ChunkDecoratorOverworldAPI.overworldConfig; - private static final NetherConfig netherConfig = ChunkDecoratorNetherAPI.netherConfig; @Override public String getModID() { return TerrainMain.MOD_ID; @@ -82,8 +80,8 @@ public static void initializeDefaultValues(){ overworldConfig.addRandomGrassBlock(Biomes.OVERWORLD_TAIGA, Block.tallgrassFern); } public static void initializeOverworldStructures() { - ChunkDecoratorOverworldAPI.structureFeatures.addStructure(OverworldFunctions::generateDungeons, null); - ChunkDecoratorOverworldAPI.structureFeatures.addStructure(OverworldFunctions::generateLabyrinths, null); + ChunkDecoratorOverworldAPI.structureFeatures.addFeature(OverworldFunctions::generateDungeons, null); + ChunkDecoratorOverworldAPI.structureFeatures.addFeature(OverworldFunctions::generateLabyrinths, null); } public static void initializeOverworldOre(){ String currentBlock = Block.blockClay.getKey(); diff --git a/src/main/java/useless/terrainapi/config/APIConfig.java b/src/main/java/useless/terrainapi/config/APIConfig.java index 28f5844..e21ffd9 100644 --- a/src/main/java/useless/terrainapi/config/APIConfig.java +++ b/src/main/java/useless/terrainapi/config/APIConfig.java @@ -6,6 +6,9 @@ public class APIConfig { @SerializedName(value = "Override Default Values") @Expose private boolean configOverride = false; + /** + * Determines if terrain api json values will be used instead of the values defined in mods + */ public boolean getConfigOverride(){ return configOverride; } diff --git a/src/main/java/useless/terrainapi/config/OreConfig.java b/src/main/java/useless/terrainapi/config/OreConfig.java index 7d7125b..7e8b1f2 100644 --- a/src/main/java/useless/terrainapi/config/OreConfig.java +++ b/src/main/java/useless/terrainapi/config/OreConfig.java @@ -9,10 +9,19 @@ import java.util.HashMap; public class OreConfig extends APIConfig { + /** + * Map of Block key and ore vein size + */ @SerializedName(value = "Ore Cluster Size") @Expose public HashMap clusterSize = new HashMap<>(); + /** + * Map of Block key and chances to generate per chunk + */ @SerializedName(value = "Chances Per Chunk") @Expose public HashMap chancesPerChunk = new HashMap<>(); + /** + * Map of Block key generation range + */ @SerializedName(value = "Vertical Range") @Expose public HashMap verticalRange = new HashMap<>(); public void setOreValues(String modID, Block block, int clusterSize, int chances, float range){ diff --git a/src/main/java/useless/terrainapi/generation/ChunkDecoratorAPI.java b/src/main/java/useless/terrainapi/generation/ChunkDecoratorAPI.java index 3e7c2fb..0e35b6f 100644 --- a/src/main/java/useless/terrainapi/generation/ChunkDecoratorAPI.java +++ b/src/main/java/useless/terrainapi/generation/ChunkDecoratorAPI.java @@ -5,7 +5,7 @@ import net.minecraft.core.world.biome.Biome; import net.minecraft.core.world.chunk.Chunk; import net.minecraft.core.world.generate.chunk.ChunkDecorator; -import net.minecraft.core.world.generate.feature.*; +import net.minecraft.core.world.generate.feature.WorldFeature; import net.minecraft.core.world.type.WorldTypes; import java.util.Random; diff --git a/src/main/java/useless/terrainapi/generation/GeneratorFeatures.java b/src/main/java/useless/terrainapi/generation/GeneratorFeatures.java index e1b3e7e..14b1935 100644 --- a/src/main/java/useless/terrainapi/generation/GeneratorFeatures.java +++ b/src/main/java/useless/terrainapi/generation/GeneratorFeatures.java @@ -1,15 +1,20 @@ package useless.terrainapi.generation; import net.minecraft.core.world.generate.feature.WorldFeature; +import org.jetbrains.annotations.ApiStatus; import java.util.ArrayList; import java.util.List; import java.util.function.Function; public class GeneratorFeatures { + @ApiStatus.Internal public List> featureFunctionsList = new ArrayList<>(); + @ApiStatus.Internal public List featureParametersList = new ArrayList<>(); + @ApiStatus.Internal public List> densityFunctionsList = new ArrayList<>(); + @ApiStatus.Internal public List densityParametersList = new ArrayList<>(); /** The Object[] are the parameters passed into the provided function, index 0 will always be populated by Biome, index 1 with Random, index 2 with Chunk, index 3 with the ChunkDecorator, and index 4 with the oreHeightModifier. Additional parameters can be added in the method. diff --git a/src/main/java/useless/terrainapi/generation/StructureFeatures.java b/src/main/java/useless/terrainapi/generation/StructureFeatures.java index d9bddf6..5c6a894 100644 --- a/src/main/java/useless/terrainapi/generation/StructureFeatures.java +++ b/src/main/java/useless/terrainapi/generation/StructureFeatures.java @@ -1,19 +1,23 @@ package useless.terrainapi.generation; +import org.jetbrains.annotations.ApiStatus; + import java.util.ArrayList; import java.util.List; import java.util.function.Function; public class StructureFeatures extends GeneratorFeatures{ - public List> featureFunctionsList = new ArrayList<>(); + @ApiStatus.Internal + public List> featureFunctionList = new ArrayList<>(); + @ApiStatus.Internal public List featureParametersList = new ArrayList<>(); /** The Object[] are the parameters passed into the provided function, index 0 will always be populated by Biome, index 1 with Random, index 2 with Chunk, index 3 with the ChunkDecorator, and index 4 with the oreHeightModifier. Additional parameters can be added in the method. * Range Modifier of -1 indicates that the feature should only generate on the surface * */ - public void addStructure(Function function, Object[] functionParameters){ - featureFunctionsList.add(function); - featureParametersList.add(functionParameters); - assert featureFunctionsList.size() == featureParametersList.size(): "Structure Features list sizes do not match!!"; + public void addFeature(Function function, Object[] additionalParameters){ + featureFunctionList.add(function); + featureParametersList.add(additionalParameters); + assert featureFunctionList.size() == featureParametersList.size(): "Structure Features list sizes do not match!!"; } } diff --git a/src/main/java/useless/terrainapi/generation/overworld/OverworldBiomeFeatures.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldBiomeFeatures.java index 693053c..3df19b8 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/OverworldBiomeFeatures.java +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldBiomeFeatures.java @@ -2,6 +2,7 @@ import net.minecraft.core.world.biome.Biome; import net.minecraft.core.world.generate.feature.WorldFeature; +import org.jetbrains.annotations.ApiStatus; import useless.terrainapi.generation.GeneratorFeatures; import useless.terrainapi.generation.Parameters; @@ -10,6 +11,7 @@ import java.util.function.Function; public class OverworldBiomeFeatures extends GeneratorFeatures { + @ApiStatus.Internal public List rangeModifierList = new ArrayList<>(); public void addFeatureSurface(WorldFeature feature, int chances, Biome[] biomes){ addFeature(feature, -1f, chances, biomes); diff --git a/src/main/java/useless/terrainapi/generation/overworld/OverworldConfig.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldConfig.java index 9e76b33..010450b 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/OverworldConfig.java +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldConfig.java @@ -83,7 +83,41 @@ public void addTreeDensity(Biome biome, int density){ } public Integer getTreeDensity(Biome biome){ return treeDensityMap.get(Registries.BIOMES.getKey(biome)); - }public Integer getTreeDensity(Biome biome, int defaultValue){ + } + + /** + * @return Biome's tree density, returns defaultValue if there is no entry for the biome + */ + @NotNull + @SuppressWarnings("unused") + public Integer getTreeDensity(Biome biome, int defaultValue){ return treeDensityMap.getOrDefault(Registries.BIOMES.getKey(biome), defaultValue); } + + /**Specifies the number of chances for lake to spawn for the specified biome + */ + @SuppressWarnings("unused") + public void addLakeDensity(Biome biome, int density){ + if (getConfigOverride() && getTreeDensity(biome) != null){ + return; + } + lakeDensityMap.put(Registries.BIOMES.getKey(biome), density); + } + + /** + * @return Biome's lake density, returns null if there is no entry for the biome + */ + @Nullable + @SuppressWarnings("unused") + public Integer getLakeDensity(Biome biome){ + return lakeDensityMap.get(Registries.BIOMES.getKey(biome)); + } + + /** + * @return Biome's lake density, returns defaultValue if there is no entry for the biome + */ + @NotNull + public Integer getLakeDensity(Biome biome, int defaultValue){ + return lakeDensityMap.getOrDefault(Registries.BIOMES.getKey(biome), defaultValue); + } } diff --git a/src/main/java/useless/terrainapi/generation/overworld/OverworldOreFeatures.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldOreFeatures.java index e19a968..788f40f 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/OverworldOreFeatures.java +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldOreFeatures.java @@ -4,6 +4,7 @@ import net.minecraft.core.world.biome.Biome; import net.minecraft.core.world.generate.feature.WorldFeature; import net.minecraft.core.world.generate.feature.WorldFeatureOre; +import org.jetbrains.annotations.ApiStatus; import useless.terrainapi.config.OreConfig; import useless.terrainapi.generation.GeneratorFeatures; import useless.terrainapi.generation.Parameters; @@ -13,6 +14,7 @@ import java.util.function.Function; public class OverworldOreFeatures extends GeneratorFeatures { + @ApiStatus.Internal public List rangeModifierList = new ArrayList<>(); public OreConfig config; public OverworldOreFeatures(OreConfig config){ diff --git a/src/main/java/useless/terrainapi/generation/overworld/OverworldRandomFeatures.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldRandomFeatures.java index 39e9226..96891e6 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/OverworldRandomFeatures.java +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldRandomFeatures.java @@ -2,6 +2,7 @@ import net.minecraft.core.world.biome.Biome; import net.minecraft.core.world.generate.feature.WorldFeature; +import org.jetbrains.annotations.ApiStatus; import useless.terrainapi.generation.GeneratorFeatures; import useless.terrainapi.generation.Parameters; @@ -10,8 +11,15 @@ import java.util.function.Function; public class OverworldRandomFeatures extends GeneratorFeatures { + @ApiStatus.Internal public List rangeModifierList = new ArrayList<>(); + @ApiStatus.Internal public List inverseProbabilityList = new ArrayList<>(); + + /**Adds a world feature entry, will only generate on the surface + * @param feature WorldFeature to generate + * @param inverseProbability Inverse of the probability, example inverseProbability of 2 means a 50% chance + */ public void addFeatureSurface(WorldFeature feature, int inverseProbability){ addFeature(feature, inverseProbability, -1f); } diff --git a/src/main/java/useless/terrainapi/util/Utilities.java b/src/main/java/useless/terrainapi/util/Utilities.java index 21e13ce..92ad4a1 100644 --- a/src/main/java/useless/terrainapi/util/Utilities.java +++ b/src/main/java/useless/terrainapi/util/Utilities.java @@ -20,4 +20,23 @@ public static boolean checkForBiomeInBiomes(Biome biome, Biome[] biomes){ } return false; } + + /**Combines two same type arrays + * @param a Array 1 + * @param b Array 2 + * @param Type of both arrays + * @return Array A + Array B + */ + @SuppressWarnings("unused") + public static T[] concatenate(T[] a, T[] b) { + int aLen = a.length; + int bLen = b.length; + + @SuppressWarnings("unchecked") + T[] c = (T[]) Array.newInstance(a.getClass().getComponentType(), aLen + bLen); + System.arraycopy(a, 0, c, 0, aLen); + System.arraycopy(b, 0, c, aLen, bLen); + + return c; + } } From 1e840aa88d485e0ca44948f2e2c374a31e9dc1f6 Mon Sep 17 00:00:00 2001 From: UselessBullets <80850784+UselessBullets@users.noreply.github.com> Date: Thu, 9 Nov 2023 23:35:50 -0600 Subject: [PATCH 05/13] version Bump --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 95b7cca..f0bcf37 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,9 +7,9 @@ bta_version=1.7.7.0_02 loader_version=0.14.19-babric.1-bta # HalpLibe -halplibe_version=2.5.0 +halplibe_version=2.7.0 # Mod -mod_version=1.2.1 +mod_version=1.3.0 mod_group=useless mod_name=terrainapi-beta From 11e4abdff67415bb41ae0df5cc7f76cbeca3ce79 Mon Sep 17 00:00:00 2001 From: UselessBullets <80850784+UselessBullets@users.noreply.github.com> Date: Fri, 10 Nov 2023 00:11:34 -0600 Subject: [PATCH 06/13] Minor Changes --- src/main/java/useless/terrainapi/TerrainInitialization.java | 3 +++ src/main/java/useless/terrainapi/TerrainMain.java | 3 ++- src/main/java/useless/terrainapi/mixin/MinecraftMixin.java | 2 +- .../java/useless/terrainapi/mixin/MinecraftServerMixin.java | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/useless/terrainapi/TerrainInitialization.java b/src/main/java/useless/terrainapi/TerrainInitialization.java index 906316c..9879266 100644 --- a/src/main/java/useless/terrainapi/TerrainInitialization.java +++ b/src/main/java/useless/terrainapi/TerrainInitialization.java @@ -76,6 +76,9 @@ public static void initializeDefaultValues(){ overworldConfig.addRandomGrassBlock(Biomes.OVERWORLD_SWAMPLAND, Block.tallgrassFern); overworldConfig.addRandomGrassBlock(Biomes.OVERWORLD_BOREAL_FOREST, Block.tallgrassFern); overworldConfig.addRandomGrassBlock(Biomes.OVERWORLD_TAIGA, Block.tallgrassFern); + + overworldConfig.addLakeDensity(Biomes.OVERWORLD_SWAMPLAND, 2); + overworldConfig.addLakeDensity(Biomes.OVERWORLD_DESERT, 2); } public static void initializeOverworldStructures() { ChunkDecoratorOverworldAPI.structureFeatures.addFeature(OverworldFunctions::generateDungeons, null); diff --git a/src/main/java/useless/terrainapi/TerrainMain.java b/src/main/java/useless/terrainapi/TerrainMain.java index fec1d59..fe982ec 100644 --- a/src/main/java/useless/terrainapi/TerrainMain.java +++ b/src/main/java/useless/terrainapi/TerrainMain.java @@ -24,8 +24,9 @@ public void onInitialize() { public static void loadModules(){ new TerrainInitialization().onInitialize(); FabricLoader.getInstance().getEntrypoints("terrain-api", TerrainAPI.class).forEach(api -> { + // Make sure the method is implemented try { - api.getClass().getDeclaredMethod("onInitialize"); // Make sure the method is implemented + api.getClass().getDeclaredMethod("onInitialize"); api.onInitialize(); } catch (NoSuchMethodException ignored) { } diff --git a/src/main/java/useless/terrainapi/mixin/MinecraftMixin.java b/src/main/java/useless/terrainapi/mixin/MinecraftMixin.java index 296111c..7cac115 100644 --- a/src/main/java/useless/terrainapi/mixin/MinecraftMixin.java +++ b/src/main/java/useless/terrainapi/mixin/MinecraftMixin.java @@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import useless.terrainapi.TerrainMain; -@Mixin(value = Minecraft.class, remap = false) +@Mixin(value = Minecraft.class, remap = false, priority = 999) public class MinecraftMixin { @Inject(method = "startGame()V", at = @At("HEAD")) private void initializeGeneration(CallbackInfo ci){ diff --git a/src/main/java/useless/terrainapi/mixin/MinecraftServerMixin.java b/src/main/java/useless/terrainapi/mixin/MinecraftServerMixin.java index 9938934..3171bdd 100644 --- a/src/main/java/useless/terrainapi/mixin/MinecraftServerMixin.java +++ b/src/main/java/useless/terrainapi/mixin/MinecraftServerMixin.java @@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import useless.terrainapi.TerrainMain; -@Mixin(value = MinecraftServer.class, remap = false) +@Mixin(value = MinecraftServer.class, remap = false, priority = 999) public class MinecraftServerMixin { @Inject(method = "startServer()Z", at = @At("HEAD")) private void initializeGeneration(CallbackInfoReturnable cir){ From d1ade6b1bc9febf7d2f3d6718a50dbb174c55a52 Mon Sep 17 00:00:00 2001 From: UselessBullets <80850784+UselessBullets@users.noreply.github.com> Date: Fri, 10 Nov 2023 00:11:45 -0600 Subject: [PATCH 07/13] Minor Optimizations --- .../api/ChunkDecoratorOverworldAPI.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java b/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java index 7684ca8..9e02a5b 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java +++ b/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java @@ -86,18 +86,28 @@ public void decorate(Chunk chunk) { public void swampFeature(int x, int z, Random random){ for (int dx = 0; dx < 16; ++dx) { for (int dz = 0; dz < 16; ++dz) { - boolean shouldPlaceWater; + if (!(random.nextFloat() < 0.5f)) continue; + int topBlock = this.world.getHeightValue(x + dx, z + dz); int id = this.world.getBlockId(x + dx, topBlock - 1, z + dz); if (id != Block.grass.id) continue; - shouldPlaceWater = random.nextFloat() < 0.5f; - if (!shouldPlaceWater) continue; + int posXId = this.world.getBlockId(x + dx + 1, topBlock - 1, z + dz); + if (posXId == 0) continue; int negXId = this.world.getBlockId(x + dx - 1, topBlock - 1, z + dz); + if (negXId == 0) continue; int posZId = this.world.getBlockId(x + dx, topBlock - 1, z + dz + 1); + if (posZId == 0) continue; int negZId = this.world.getBlockId(x + dx, topBlock - 1, z + dz - 1); + if (negZId == 0) continue; int negYId = this.world.getBlockId(x + dx, topBlock - 2, z + dz); - if (posXId == 0 || !Block.blocksList[posXId].blockMaterial.isSolid() && Block.blocksList[posXId].blockMaterial != Material.water || negXId == 0 || !Block.blocksList[negXId].blockMaterial.isSolid() && Block.blocksList[negXId].blockMaterial != Material.water || posZId == 0 || !Block.blocksList[posZId].blockMaterial.isSolid() && Block.blocksList[posZId].blockMaterial != Material.water || negZId == 0 || !Block.blocksList[negZId].blockMaterial.isSolid() && Block.blocksList[negZId].blockMaterial != Material.water || negYId == 0 || !Block.blocksList[negYId].blockMaterial.isSolid()) continue; + if (negYId == 0) continue; + + if ((!Block.blocksList[posXId].blockMaterial.isSolid() && Block.blocksList[posXId].blockMaterial != Material.water) + || (!Block.blocksList[negXId].blockMaterial.isSolid() && Block.blocksList[negXId].blockMaterial != Material.water) + || (!Block.blocksList[posZId].blockMaterial.isSolid() && Block.blocksList[posZId].blockMaterial != Material.water) + || (!Block.blocksList[negZId].blockMaterial.isSolid() && Block.blocksList[negZId].blockMaterial != Material.water) + || !Block.blocksList[negYId].blockMaterial.isSolid()) continue; this.world.setBlock(x + dx, topBlock - 1, z + dz, Block.fluidWaterStill.id); this.world.setBlock(x + dx, topBlock, z + dz, 0); } From b244700916b649a1eb1533f761faddf245311f54 Mon Sep 17 00:00:00 2001 From: UselessBullets <80850784+UselessBullets@users.noreply.github.com> Date: Fri, 10 Nov 2023 08:38:55 -0600 Subject: [PATCH 08/13] Refactors --- .../terrainapi/TerrainInitialization.java | 5 +- .../overworld/OverworldFunctions.java | 93 ++++++++++++++++++- .../api/ChunkDecoratorOverworldAPI.java | 63 +------------ 3 files changed, 96 insertions(+), 65 deletions(-) diff --git a/src/main/java/useless/terrainapi/TerrainInitialization.java b/src/main/java/useless/terrainapi/TerrainInitialization.java index 9879266..0675618 100644 --- a/src/main/java/useless/terrainapi/TerrainInitialization.java +++ b/src/main/java/useless/terrainapi/TerrainInitialization.java @@ -78,9 +78,12 @@ public static void initializeDefaultValues(){ overworldConfig.addRandomGrassBlock(Biomes.OVERWORLD_TAIGA, Block.tallgrassFern); overworldConfig.addLakeDensity(Biomes.OVERWORLD_SWAMPLAND, 2); - overworldConfig.addLakeDensity(Biomes.OVERWORLD_DESERT, 2); + overworldConfig.addLakeDensity(Biomes.OVERWORLD_DESERT, 0); } public static void initializeOverworldStructures() { + ChunkDecoratorOverworldAPI.structureFeatures.addFeature(OverworldFunctions::generateSwamp, null); + ChunkDecoratorOverworldAPI.structureFeatures.addFeature(OverworldFunctions::generateLakeFeature, null); + ChunkDecoratorOverworldAPI.structureFeatures.addFeature(OverworldFunctions::generateLavaLakeFeature, null); ChunkDecoratorOverworldAPI.structureFeatures.addFeature(OverworldFunctions::generateDungeons, null); ChunkDecoratorOverworldAPI.structureFeatures.addFeature(OverworldFunctions::generateLabyrinths, null); } diff --git a/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java index 6bb85a3..69ca54e 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java @@ -1,11 +1,10 @@ package useless.terrainapi.generation.overworld; import net.minecraft.core.block.Block; +import net.minecraft.core.block.material.Material; import net.minecraft.core.world.biome.Biome; -import net.minecraft.core.world.generate.feature.WorldFeature; -import net.minecraft.core.world.generate.feature.WorldFeatureDungeon; -import net.minecraft.core.world.generate.feature.WorldFeatureLabyrinth; -import net.minecraft.core.world.generate.feature.WorldFeatureTallGrass; +import net.minecraft.core.world.biome.Biomes; +import net.minecraft.core.world.generate.feature.*; import org.jetbrains.annotations.Nullable; import useless.terrainapi.generation.Parameters; import useless.terrainapi.generation.overworld.api.ChunkDecoratorOverworldAPI; @@ -153,4 +152,90 @@ public static Void generateLabyrinths(Parameters parameters){ } return null; } + /**Vanilla swamp generation code + * @param parameters Parameters Container + * @return null + */ + @Nullable + public static Void generateSwamp(Parameters parameters){ + if (parameters.biome != Biomes.OVERWORLD_SWAMPLAND) return null; + int x = parameters.chunk.xPosition * 16; + int z = parameters.chunk.zPosition * 16; + ChunkDecoratorOverworldAPI decorator = (ChunkDecoratorOverworldAPI) parameters.decorator; + + Random swampRand = new Random(decorator.chunkSeed); + + for (int dx = 0; dx < 16; ++dx) { + for (int dz = 0; dz < 16; ++dz) { + if (!(swampRand.nextFloat() < 0.5f)) continue; + + int topBlock = decorator.world.getHeightValue(x + dx, z + dz); + int id = decorator.world.getBlockId(x + dx, topBlock - 1, z + dz); + if (id != Block.grass.id) continue; + + int posXId = decorator.world.getBlockId(x + dx + 1, topBlock - 1, z + dz); + if (posXId == 0) continue; + int negXId = decorator.world.getBlockId(x + dx - 1, topBlock - 1, z + dz); + if (negXId == 0) continue; + int posZId = decorator.world.getBlockId(x + dx, topBlock - 1, z + dz + 1); + if (posZId == 0) continue; + int negZId = decorator.world.getBlockId(x + dx, topBlock - 1, z + dz - 1); + if (negZId == 0) continue; + int negYId = decorator.world.getBlockId(x + dx, topBlock - 2, z + dz); + if (negYId == 0) continue; + + if ((!Block.blocksList[posXId].blockMaterial.isSolid() && Block.blocksList[posXId].blockMaterial != Material.water) + || (!Block.blocksList[negXId].blockMaterial.isSolid() && Block.blocksList[negXId].blockMaterial != Material.water) + || (!Block.blocksList[posZId].blockMaterial.isSolid() && Block.blocksList[posZId].blockMaterial != Material.water) + || (!Block.blocksList[negZId].blockMaterial.isSolid() && Block.blocksList[negZId].blockMaterial != Material.water) + || !Block.blocksList[negYId].blockMaterial.isSolid()) continue; + decorator.world.setBlock(x + dx, topBlock - 1, z + dz, Block.fluidWaterStill.id); + decorator.world.setBlock(x + dx, topBlock, z + dz, 0); + } + } + return null; + } + /**Vanilla lake generation code + * @param parameters Parameters Container + * @return null + */ + @Nullable + public static Void generateLakeFeature(Parameters parameters){ + int lakeChance = overworldConfig.getLakeDensity(parameters.biome, overworldConfig.defaultLakeDensity); + int x = parameters.chunk.xPosition * 16; + int z = parameters.chunk.zPosition * 16; + + ChunkDecoratorOverworldAPI decorator = (ChunkDecoratorOverworldAPI) parameters.decorator; + + if (lakeChance != 0 && parameters.random.nextInt(lakeChance) == 0) { + int fluid = Block.fluidWaterStill.id; + if (parameters.biome.hasSurfaceSnow()) { + fluid = Block.ice.id; + } + int i1 = x + parameters.random.nextInt(16) + 8; + int l4 = decorator.minY + parameters.random.nextInt(decorator.rangeY); + int i8 = z + parameters.random.nextInt(16) + 8; + new WorldFeatureLake(fluid).generate(decorator.world, parameters.random, i1, l4, i8); + } + return null; + } + /**Vanilla lava lake generation code + * @param parameters Parameters Container + * @return null + */ + @Nullable + public static Void generateLavaLakeFeature(Parameters parameters){ + int x = parameters.chunk.xPosition * 16; + int z = parameters.chunk.zPosition * 16; + ChunkDecoratorOverworldAPI decorator = (ChunkDecoratorOverworldAPI) parameters.decorator; + if (parameters.random.nextInt(8) == 0) { + int xf = x + parameters.random.nextInt(16) + 8; + int yf = decorator.minY + parameters.random.nextInt(parameters.random.nextInt(decorator.rangeY - decorator.rangeY / 16) + decorator.rangeY / 16); + int zf = z + parameters.random.nextInt(16) + 8; + if (yf < decorator.minY + decorator.rangeY / 2 || parameters.random.nextInt(10) == 0) { + new WorldFeatureLake(Block.fluidLavaStill.id).generate(decorator.world, parameters.random, xf, yf, zf); + } + } + return null; + } } diff --git a/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java b/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java index 9e02a5b..20655ba 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java +++ b/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java @@ -32,6 +32,7 @@ public class ChunkDecoratorOverworldAPI extends ChunkDecoratorAPI { public static OverworldOreFeatures oreFeatures = new OverworldOreFeatures(overworldConfig); public static OverworldRandomFeatures randomFeatures = new OverworldRandomFeatures(); public static OverworldBiomeFeatures biomeFeatures = new OverworldBiomeFeatures(); + public long chunkSeed; protected ChunkDecoratorOverworldAPI(World world, int treeDensityOverride) { super(world); this.treeDensityOverride = treeDensityOverride; @@ -56,19 +57,13 @@ public void decorate(Chunk chunk) { Random random = new Random(this.world.getRandomSeed()); long l1 = random.nextLong() / 2L * 2L + 1L; long l2 = random.nextLong() / 2L * 2L + 1L; - random.setSeed((long)chunkX * l1 + (long)chunkZ * l2 ^ this.world.getRandomSeed()); - Random swampRand = new Random((long)chunkX * l1 + (long)chunkZ * l2 ^ this.world.getRandomSeed()); + chunkSeed = (long)chunkX * l1 + (long)chunkZ * l2 ^ this.world.getRandomSeed(); + random.setSeed(chunkSeed); BlockSand.fallInstantly = true; - if (biome == Biomes.OVERWORLD_SWAMPLAND){ - swampFeature(xCoord, zCoord, swampRand); - } - parameterBase = new Parameters(biome, random, chunk, this); - generateLakeFeature(overworldConfig.getLakeDensity(biome, overworldConfig.defaultLakeDensity), xCoord, zCoord, biome, random); - generateStructures(biome, chunk, random); generateOreFeatures(biome, xCoord, zCoord, random, chunk); generateBiomeFeature(biome,xCoord, zCoord, random, chunk); @@ -83,58 +78,6 @@ public void decorate(Chunk chunk) { } @ApiStatus.Internal - public void swampFeature(int x, int z, Random random){ - for (int dx = 0; dx < 16; ++dx) { - for (int dz = 0; dz < 16; ++dz) { - if (!(random.nextFloat() < 0.5f)) continue; - - int topBlock = this.world.getHeightValue(x + dx, z + dz); - int id = this.world.getBlockId(x + dx, topBlock - 1, z + dz); - if (id != Block.grass.id) continue; - - int posXId = this.world.getBlockId(x + dx + 1, topBlock - 1, z + dz); - if (posXId == 0) continue; - int negXId = this.world.getBlockId(x + dx - 1, topBlock - 1, z + dz); - if (negXId == 0) continue; - int posZId = this.world.getBlockId(x + dx, topBlock - 1, z + dz + 1); - if (posZId == 0) continue; - int negZId = this.world.getBlockId(x + dx, topBlock - 1, z + dz - 1); - if (negZId == 0) continue; - int negYId = this.world.getBlockId(x + dx, topBlock - 2, z + dz); - if (negYId == 0) continue; - - if ((!Block.blocksList[posXId].blockMaterial.isSolid() && Block.blocksList[posXId].blockMaterial != Material.water) - || (!Block.blocksList[negXId].blockMaterial.isSolid() && Block.blocksList[negXId].blockMaterial != Material.water) - || (!Block.blocksList[posZId].blockMaterial.isSolid() && Block.blocksList[posZId].blockMaterial != Material.water) - || (!Block.blocksList[negZId].blockMaterial.isSolid() && Block.blocksList[negZId].blockMaterial != Material.water) - || !Block.blocksList[negYId].blockMaterial.isSolid()) continue; - this.world.setBlock(x + dx, topBlock - 1, z + dz, Block.fluidWaterStill.id); - this.world.setBlock(x + dx, topBlock, z + dz, 0); - } - } - } - @ApiStatus.Internal - public void generateLakeFeature(int lakeChance, int x, int z, Biome biome, Random random){ - if (lakeChance != 0 && random.nextInt(lakeChance) == 0) { - int fluid = Block.fluidWaterStill.id; - if (biome.hasSurfaceSnow()) { - fluid = Block.ice.id; - } - int i1 = x + random.nextInt(16) + 8; - int l4 = minY + random.nextInt(rangeY); - int i8 = z + random.nextInt(16) + 8; - new WorldFeatureLake(fluid).generate(this.world, random, i1, l4, i8); - } - if (random.nextInt(8) == 0) { - int xf = x + random.nextInt(16) + 8; - int yf = minY + random.nextInt(random.nextInt(rangeY - rangeY / 16) + rangeY / 16); - int zf = z + random.nextInt(16) + 8; - if (yf < minY + rangeY / 2 || random.nextInt(10) == 0) { - new WorldFeatureLake(Block.fluidLavaStill.id).generate(this.world, random, xf, yf, zf); - } - } - } - @ApiStatus.Internal public void generateStructures(Biome biome, Chunk chunk, Random random){ int featureSize = structureFeatures.featureFunctionList.size(); for (int i = 0; i < featureSize; i++) { From 9ad6e66aafcda4a172a4b839b6a66a2a6d124023 Mon Sep 17 00:00:00 2001 From: UselessBullets <80850784+UselessBullets@users.noreply.github.com> Date: Fri, 10 Nov 2023 13:48:26 -0600 Subject: [PATCH 09/13] More world types (#11) * Added Retro Worldtype API * Abstract decorator code slightly * Bug Fixes * Woods World type * Paradise Support * Floating Worldtype Support * added Hell WorldType * Tree Fix * Update OverworldInitialization.java --- .../terrainapi/TerrainInitialization.java | 131 ---------------- .../java/useless/terrainapi/TerrainMain.java | 1 + .../generation/ChunkDecoratorAPI.java | 28 +++- .../terrainapi/generation/Parameters.java | 7 +- .../api/ChunkGeneratorFloatingAPI.java | 14 ++ .../generation/hell/HellConfig.java | 10 ++ .../generation/hell/HellFunctions.java | 141 ++++++++++++++++++ .../api/ChunkDecoratorOverworldHellAPI.java | 106 +++++++++++++ .../api/ChunkGeneratorOverworldHellAPI.java | 13 ++ .../nether/api/ChunkDecoratorNetherAPI.java | 29 ++-- .../overworld/OverworldFunctions.java | 87 +++++++---- .../api/ChunkDecoratorOverworldAPI.java | 50 ++----- .../api/ChunkGeneratorParadiseAPI.java | 15 ++ .../generation/retro/RetroConfig.java | 6 + .../generation/retro/RetroFunctions.java | 77 ++++++++++ .../retro/api/ChunkDecoratorRetroAPI.java | 103 +++++++++++++ .../retro/api/ChunkGeneratorRetroAPI.java | 13 ++ .../api/ChunkGeneratorOverworldWoodsAPI.java | 14 ++ .../initialization/BaseInitialization.java | 19 +++ .../initialization/TerrainInitialization.java | 26 ++++ .../worldtypes/HellInitialization.java | 63 ++++++++ .../worldtypes/NetherInitialization.java | 40 +++++ .../worldtypes/OverworldInitialization.java | 119 +++++++++++++++ .../worldtypes/RetroInitialization.java | 64 ++++++++ .../worldtypes/WorldTypeFloatingMixin.java | 17 +++ .../worldtypes/WorldTypeNetherMixin.java | 18 +++ .../WorldTypeOverworldHellMixin.java | 17 +++ .../WorldTypeOverworldMixin.java | 2 +- .../WorldTypeOverworldRetroMixin.java | 18 +++ .../WorldTypeOverworldWoodsMixin.java | 18 +++ .../worldtypes/WorldTypeParadiseMixin.java | 18 +++ src/main/resources/fabric.mod.json | 2 +- src/main/resources/terrainapi.mixins.json | 8 +- 33 files changed, 1073 insertions(+), 221 deletions(-) delete mode 100644 src/main/java/useless/terrainapi/TerrainInitialization.java create mode 100644 src/main/java/useless/terrainapi/generation/floating/api/ChunkGeneratorFloatingAPI.java create mode 100644 src/main/java/useless/terrainapi/generation/hell/HellConfig.java create mode 100644 src/main/java/useless/terrainapi/generation/hell/HellFunctions.java create mode 100644 src/main/java/useless/terrainapi/generation/hell/api/ChunkDecoratorOverworldHellAPI.java create mode 100644 src/main/java/useless/terrainapi/generation/hell/api/ChunkGeneratorOverworldHellAPI.java create mode 100644 src/main/java/useless/terrainapi/generation/paradise/api/ChunkGeneratorParadiseAPI.java create mode 100644 src/main/java/useless/terrainapi/generation/retro/RetroConfig.java create mode 100644 src/main/java/useless/terrainapi/generation/retro/RetroFunctions.java create mode 100644 src/main/java/useless/terrainapi/generation/retro/api/ChunkDecoratorRetroAPI.java create mode 100644 src/main/java/useless/terrainapi/generation/retro/api/ChunkGeneratorRetroAPI.java create mode 100644 src/main/java/useless/terrainapi/generation/woods/api/ChunkGeneratorOverworldWoodsAPI.java create mode 100644 src/main/java/useless/terrainapi/initialization/BaseInitialization.java create mode 100644 src/main/java/useless/terrainapi/initialization/TerrainInitialization.java create mode 100644 src/main/java/useless/terrainapi/initialization/worldtypes/HellInitialization.java create mode 100644 src/main/java/useless/terrainapi/initialization/worldtypes/NetherInitialization.java create mode 100644 src/main/java/useless/terrainapi/initialization/worldtypes/OverworldInitialization.java create mode 100644 src/main/java/useless/terrainapi/initialization/worldtypes/RetroInitialization.java create mode 100644 src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeFloatingMixin.java create mode 100644 src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeNetherMixin.java create mode 100644 src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeOverworldHellMixin.java rename src/main/java/useless/terrainapi/mixin/{ => worldtypes}/WorldTypeOverworldMixin.java (95%) create mode 100644 src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeOverworldRetroMixin.java create mode 100644 src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeOverworldWoodsMixin.java create mode 100644 src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeParadiseMixin.java diff --git a/src/main/java/useless/terrainapi/TerrainInitialization.java b/src/main/java/useless/terrainapi/TerrainInitialization.java deleted file mode 100644 index 0675618..0000000 --- a/src/main/java/useless/terrainapi/TerrainInitialization.java +++ /dev/null @@ -1,131 +0,0 @@ -package useless.terrainapi; - -import net.minecraft.core.block.Block; -import net.minecraft.core.world.biome.Biome; -import net.minecraft.core.world.biome.Biomes; -import net.minecraft.core.world.generate.feature.*; -import useless.terrainapi.api.TerrainAPI; -import useless.terrainapi.generation.Parameters; -import useless.terrainapi.generation.nether.NetherFunctions; -import useless.terrainapi.generation.nether.api.ChunkDecoratorNetherAPI; -import useless.terrainapi.generation.overworld.OverworldConfig; -import useless.terrainapi.generation.overworld.OverworldFunctions; -import useless.terrainapi.generation.overworld.api.ChunkDecoratorOverworldAPI; - -public class TerrainInitialization implements TerrainAPI { - private static boolean hasInitialized = false; - private static final OverworldConfig overworldConfig = ChunkDecoratorOverworldAPI.overworldConfig; - @Override - public String getModID() { - return TerrainMain.MOD_ID; - } - @Override - public void onInitialize() { - if (hasInitialized) {return;} - hasInitialized = true; - initializeDefaultValues(); - - initializeOverworldStructures(); - initializeOverworldOre(); - initializeOverworldRandom(); - initializeOverworldBiome(); - - initializeNether(); - } - public static void initializeDefaultValues(){ - overworldConfig.setOreValues(TerrainMain.MOD_ID, Block.blockClay, 32, 20, 1f); - - overworldConfig.addGrassDensity(Biomes.OVERWORLD_FOREST, 2); - overworldConfig.addGrassDensity(Biomes.OVERWORLD_MEADOW, 2); - overworldConfig.addGrassDensity(Biomes.OVERWORLD_RAINFOREST, 10); - overworldConfig.addGrassDensity(Biomes.OVERWORLD_DESERT, 5); - overworldConfig.addGrassDensity(Biomes.OVERWORLD_SEASONAL_FOREST, 2); - overworldConfig.addGrassDensity(Biomes.OVERWORLD_TAIGA, 1); - overworldConfig.addGrassDensity(Biomes.OVERWORLD_BOREAL_FOREST, 5); - overworldConfig.addGrassDensity(Biomes.OVERWORLD_PLAINS, 10); - overworldConfig.addGrassDensity(Biomes.OVERWORLD_SWAMPLAND, 4); - overworldConfig.addGrassDensity(Biomes.OVERWORLD_SHRUBLAND, 2); - overworldConfig.addGrassDensity(Biomes.OVERWORLD_OUTBACK_GRASSY, 25); - overworldConfig.addGrassDensity(Biomes.OVERWORLD_BIRCH_FOREST, 10); - - overworldConfig.addFlowerDensity(Biomes.OVERWORLD_SEASONAL_FOREST, 1); - overworldConfig.addFlowerDensity(Biomes.OVERWORLD_MEADOW, 2); - overworldConfig.addFlowerDensity(Biomes.OVERWORLD_BOREAL_FOREST, 2); - overworldConfig.addFlowerDensity(Biomes.OVERWORLD_SHRUBLAND, 1); - - overworldConfig.addYellowFlowerDensity(Biomes.OVERWORLD_FOREST, 2); - overworldConfig.addYellowFlowerDensity(Biomes.OVERWORLD_SWAMPLAND, 2); - overworldConfig.addYellowFlowerDensity(Biomes.OVERWORLD_TAIGA, 2); - overworldConfig.addYellowFlowerDensity(Biomes.OVERWORLD_PLAINS, 3); - overworldConfig.addYellowFlowerDensity(Biomes.OVERWORLD_OUTBACK_GRASSY, 2); - overworldConfig.addYellowFlowerDensity(Biomes.OVERWORLD_OUTBACK, 2); - - overworldConfig.addTreeDensity(Biomes.OVERWORLD_FOREST, 5); - overworldConfig.addTreeDensity(Biomes.OVERWORLD_BIRCH_FOREST, 4); - overworldConfig.addTreeDensity(Biomes.OVERWORLD_RAINFOREST, 10); - overworldConfig.addTreeDensity(Biomes.OVERWORLD_SEASONAL_FOREST, 2); - overworldConfig.addTreeDensity(Biomes.OVERWORLD_TAIGA, 5); - overworldConfig.addTreeDensity(Biomes.OVERWORLD_BOREAL_FOREST, 3); - overworldConfig.addTreeDensity(Biomes.OVERWORLD_DESERT, -1000); - overworldConfig.addTreeDensity(Biomes.OVERWORLD_TUNDRA, -1000); - overworldConfig.addTreeDensity(Biomes.OVERWORLD_PLAINS, -1000); - overworldConfig.addTreeDensity(Biomes.OVERWORLD_SWAMPLAND, 4); - overworldConfig.addTreeDensity(Biomes.OVERWORLD_OUTBACK_GRASSY, 0); - - overworldConfig.addRandomGrassBlock(Biomes.OVERWORLD_RAINFOREST, Block.tallgrassFern); - overworldConfig.addRandomGrassBlock(Biomes.OVERWORLD_SWAMPLAND, Block.tallgrassFern); - overworldConfig.addRandomGrassBlock(Biomes.OVERWORLD_BOREAL_FOREST, Block.tallgrassFern); - overworldConfig.addRandomGrassBlock(Biomes.OVERWORLD_TAIGA, Block.tallgrassFern); - - overworldConfig.addLakeDensity(Biomes.OVERWORLD_SWAMPLAND, 2); - overworldConfig.addLakeDensity(Biomes.OVERWORLD_DESERT, 0); - } - public static void initializeOverworldStructures() { - ChunkDecoratorOverworldAPI.structureFeatures.addFeature(OverworldFunctions::generateSwamp, null); - ChunkDecoratorOverworldAPI.structureFeatures.addFeature(OverworldFunctions::generateLakeFeature, null); - ChunkDecoratorOverworldAPI.structureFeatures.addFeature(OverworldFunctions::generateLavaLakeFeature, null); - ChunkDecoratorOverworldAPI.structureFeatures.addFeature(OverworldFunctions::generateDungeons, null); - ChunkDecoratorOverworldAPI.structureFeatures.addFeature(OverworldFunctions::generateLabyrinths, null); - } - public static void initializeOverworldOre(){ - String currentBlock = Block.blockClay.getKey(); - ChunkDecoratorOverworldAPI.oreFeatures.addFeature(new WorldFeatureClay(overworldConfig.clusterSize.get(currentBlock)), overworldConfig.chancesPerChunk.get(currentBlock), overworldConfig.verticalRange.get(currentBlock)); - ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.dirt, 32, 20, 1f, false); - ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.gravel, 32, 10, 1f, false); - ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.oreCoalStone, 16, 20, 1f, true); - ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.oreIronStone, 8, 20, 1/2f, true); - ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.oreGoldStone, 8, 2, 1/4f, true); - ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.oreRedstoneStone, 7, 8, 1/8f, true); - ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.oreDiamondStone, 7, 1, 1/8f, true); - ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.mossStone, 32, 1, 1/2f, true); - ChunkDecoratorOverworldAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.oreLapisStone, 6, 1, 1/8f, true); - } - public static void initializeOverworldRandom(){ - ChunkDecoratorOverworldAPI.randomFeatures.addFeature(new WorldFeatureFlowers(Block.flowerRed.id), 2, 1); - ChunkDecoratorOverworldAPI.randomFeatures.addFeature(new WorldFeatureFlowers(Block.mushroomBrown.id), 4, 1); - ChunkDecoratorOverworldAPI.randomFeatures.addFeature(new WorldFeatureFlowers(Block.mushroomRed.id), 8, 1); - ChunkDecoratorOverworldAPI.randomFeatures.addFeatureSurface(new WorldFeatureSugarCane(), 5); - ChunkDecoratorOverworldAPI.randomFeatures.addFeatureSurface(new WorldFeaturePumpkin(), 128); - ChunkDecoratorOverworldAPI.randomFeatures.addFeatureSurface(new WorldFeatureSponge(), 64); - } - public static void initializeOverworldBiome(){ - ChunkDecoratorOverworldAPI.biomeFeatures.addFeatureSurface(new WorldFeatureRichScorchedDirt(10), 1, new Biome[]{Biomes.OVERWORLD_OUTBACK, Biomes.OVERWORLD_OUTBACK_GRASSY}); - ChunkDecoratorOverworldAPI.biomeFeatures.addFeature(OverworldFunctions::getTreeFeature, null, OverworldFunctions::getTreeDensity, null, -1f); - ChunkDecoratorOverworldAPI.biomeFeatures.addFeatureSurface(new WorldFeatureSugarCaneTall(), 1, new Biome[]{Biomes.OVERWORLD_RAINFOREST}); - ChunkDecoratorOverworldAPI.biomeFeatures.addFeature(OverworldFunctions::flowerTypeCondition, null, (Parameters x) -> ChunkDecoratorOverworldAPI.overworldConfig.getFlowerDensity(x.biome, 0), null, 1f); - ChunkDecoratorOverworldAPI.biomeFeatures.addFeature((Parameters x) -> new WorldFeatureFlowers(Block.flowerYellow.id), null, (Parameters x) -> ChunkDecoratorOverworldAPI.overworldConfig.getYellowFlowerDensity(x.biome, 0), null, 1); - ChunkDecoratorOverworldAPI.biomeFeatures.addFeature(OverworldFunctions::grassTypeCondition, null, (Parameters x) -> ChunkDecoratorOverworldAPI.overworldConfig.getGrassDensity(x.biome, 0), null, 1); - ChunkDecoratorOverworldAPI.biomeFeatures.addFeature(new WorldFeatureSpinifexPatch(), 1, 4, new Biome[]{Biomes.OVERWORLD_OUTBACK}); - ChunkDecoratorOverworldAPI.biomeFeatures.addFeature(new WorldFeatureDeadBush(Block.deadbush.id), 1, 2, new Biome[]{Biomes.OVERWORLD_DESERT}); - ChunkDecoratorOverworldAPI.biomeFeatures.addFeature(new WorldFeatureCactus(), 1, 10, new Biome[]{Biomes.OVERWORLD_DESERT}); - } - public static void initializeNether(){ - ChunkDecoratorNetherAPI.oreFeatures.addFeature(new WorldFeatureNetherLava(Block.fluidLavaFlowing.id), 8,120/128f); - ChunkDecoratorNetherAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.oreNethercoalNetherrack, 12, 10, 120/128f, false); - ChunkDecoratorNetherAPI.oreFeatures.addFeature((Parameters x) -> new WorldFeatureFire(), null, NetherFunctions::netherFireDensity, null, 120/128f); - ChunkDecoratorNetherAPI.oreFeatures.addFeature((Parameters x) -> new WorldFeatureGlowstoneA(), null, NetherFunctions::netherFireDensity, null, 120/128f); - ChunkDecoratorNetherAPI.oreFeatures.addFeature(new WorldFeatureGlowstoneB(), 10, 120/128f); - ChunkDecoratorNetherAPI.randomFeatures.addFeature(new WorldFeatureLake(Block.fluidLavaStill.id), 8, 120/128f); - } -} - diff --git a/src/main/java/useless/terrainapi/TerrainMain.java b/src/main/java/useless/terrainapi/TerrainMain.java index fe982ec..1a65483 100644 --- a/src/main/java/useless/terrainapi/TerrainMain.java +++ b/src/main/java/useless/terrainapi/TerrainMain.java @@ -10,6 +10,7 @@ import org.slf4j.LoggerFactory; import useless.terrainapi.api.TerrainAPI; import useless.terrainapi.config.ConfigManager; +import useless.terrainapi.initialization.TerrainInitialization; public class TerrainMain implements ModInitializer { diff --git a/src/main/java/useless/terrainapi/generation/ChunkDecoratorAPI.java b/src/main/java/useless/terrainapi/generation/ChunkDecoratorAPI.java index 80f054d..be4b68d 100644 --- a/src/main/java/useless/terrainapi/generation/ChunkDecoratorAPI.java +++ b/src/main/java/useless/terrainapi/generation/ChunkDecoratorAPI.java @@ -1,6 +1,7 @@ package useless.terrainapi.generation; import net.minecraft.core.block.Block; +import net.minecraft.core.block.BlockSand; import net.minecraft.core.world.World; import net.minecraft.core.world.biome.Biome; import net.minecraft.core.world.chunk.Chunk; @@ -17,6 +18,8 @@ public abstract class ChunkDecoratorAPI implements ChunkDecorator { public final int maxY; public final int rangeY; public final float oreHeightModifier; + public long chunkSeed; + protected Parameters parameterBase; protected ChunkDecoratorAPI(World world) { this.world = world; @@ -26,8 +29,31 @@ protected ChunkDecoratorAPI(World world) { this.oreHeightModifier = (float)rangeY / 128.0f; } @Override + public void decorate(Chunk chunk){ + int chunkX = chunk.xPosition; + int chunkZ = chunk.zPosition; + + int xCoord = chunkX * 16; + int zCoord = chunkZ * 16; + int yCoord = this.world.getHeightValue(xCoord + 16, zCoord + 16); + + Biome biome = this.world.getBlockBiome(xCoord + 16, yCoord, zCoord + 16); + + Random random = new Random(this.world.getRandomSeed()); + long l1 = random.nextLong() / 2L * 2L + 1L; + long l2 = random.nextLong() / 2L * 2L + 1L; + chunkSeed = (long)chunkX * l1 + (long)chunkZ * l2 ^ this.world.getRandomSeed(); + random.setSeed(chunkSeed); + parameterBase = new Parameters(biome, random, chunk, this); + + BlockSand.fallInstantly = true; + + decorateAPI(); + + BlockSand.fallInstantly = false; + } @ApiStatus.Internal - public abstract void decorate(Chunk chunk); + public abstract void decorateAPI(); @ApiStatus.Internal public abstract void generateStructures(Biome biome, Chunk chunk, Random random); @ApiStatus.Internal diff --git a/src/main/java/useless/terrainapi/generation/Parameters.java b/src/main/java/useless/terrainapi/generation/Parameters.java index 594f198..81940e2 100644 --- a/src/main/java/useless/terrainapi/generation/Parameters.java +++ b/src/main/java/useless/terrainapi/generation/Parameters.java @@ -2,7 +2,6 @@ import net.minecraft.core.world.biome.Biome; import net.minecraft.core.world.chunk.Chunk; -import net.minecraft.core.world.generate.chunk.ChunkDecorator; import java.util.Random; @@ -13,13 +12,13 @@ public class Parameters { public Biome biome; public Random random; public Chunk chunk; - public ChunkDecorator decorator; + public ChunkDecoratorAPI decorator; public Object[] customParameters = new Object[0]; - public Parameters(Biome biome, Random random, Chunk chunk, ChunkDecorator chunkDecorator, Object[] customParameters){ + public Parameters(Biome biome, Random random, Chunk chunk, ChunkDecoratorAPI chunkDecorator, Object[] customParameters){ this(biome, random, chunk, chunkDecorator); this.customParameters = customParameters; } - public Parameters(Biome biome, Random random, Chunk chunk, ChunkDecorator chunkDecorator){ + public Parameters(Biome biome, Random random, Chunk chunk, ChunkDecoratorAPI chunkDecorator){ this.biome = biome; this.random = random; this.chunk = chunk; diff --git a/src/main/java/useless/terrainapi/generation/floating/api/ChunkGeneratorFloatingAPI.java b/src/main/java/useless/terrainapi/generation/floating/api/ChunkGeneratorFloatingAPI.java new file mode 100644 index 0000000..7bcf957 --- /dev/null +++ b/src/main/java/useless/terrainapi/generation/floating/api/ChunkGeneratorFloatingAPI.java @@ -0,0 +1,14 @@ +package useless.terrainapi.generation.floating.api; + +import net.minecraft.core.world.World; +import net.minecraft.core.world.generate.MapGenCaves; +import net.minecraft.core.world.generate.chunk.perlin.ChunkGeneratorPerlin; +import net.minecraft.core.world.generate.chunk.perlin.overworld.SurfaceGeneratorOverworld; +import net.minecraft.core.world.generate.chunk.perlin.paradise.TerrainGeneratorParadise; +import useless.terrainapi.generation.overworld.api.ChunkDecoratorOverworldAPI; + +public class ChunkGeneratorFloatingAPI extends ChunkGeneratorPerlin { + public ChunkGeneratorFloatingAPI(World world) { + super(world, new ChunkDecoratorOverworldAPI(world), new TerrainGeneratorParadise(world), new SurfaceGeneratorOverworld(world), new MapGenCaves(false)); + } +} diff --git a/src/main/java/useless/terrainapi/generation/hell/HellConfig.java b/src/main/java/useless/terrainapi/generation/hell/HellConfig.java new file mode 100644 index 0000000..de95363 --- /dev/null +++ b/src/main/java/useless/terrainapi/generation/hell/HellConfig.java @@ -0,0 +1,10 @@ +package useless.terrainapi.generation.hell; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; +import useless.terrainapi.config.OreConfig; + +public class HellConfig extends OreConfig { + @SerializedName("Inverse Leaves Probability") @Expose + public int invLeavesProbability = 1234; +} diff --git a/src/main/java/useless/terrainapi/generation/hell/HellFunctions.java b/src/main/java/useless/terrainapi/generation/hell/HellFunctions.java new file mode 100644 index 0000000..e505bac --- /dev/null +++ b/src/main/java/useless/terrainapi/generation/hell/HellFunctions.java @@ -0,0 +1,141 @@ +package useless.terrainapi.generation.hell; + +import net.minecraft.core.block.Block; +import net.minecraft.core.world.generate.feature.WorldFeature; +import net.minecraft.core.world.generate.feature.WorldFeatureLabyrinth; +import net.minecraft.core.world.generate.feature.WorldFeatureLake; +import net.minecraft.core.world.generate.feature.WorldFeatureLiquid; +import net.minecraft.core.world.generate.feature.tree.WorldFeatureTree; +import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeFancy; +import org.jetbrains.annotations.Nullable; +import useless.terrainapi.generation.Parameters; +import useless.terrainapi.generation.hell.api.ChunkDecoratorOverworldHellAPI; + +import java.util.Random; + +public class HellFunctions { + public static HellConfig hellConfig = ChunkDecoratorOverworldHellAPI.hellConfig; + /**Vanilla labyrinth generation code + * @param parameters Parameters Container + * @return null + */ + @Nullable + public static Void generateLabyrinths(Parameters parameters){ + int x = parameters.chunk.xPosition * 16; + int z = parameters.chunk.zPosition * 16; + for (int i = 0; i < 1; ++i) { + int xPos = x + parameters.random.nextInt(16) + 8; + int zPos = z + parameters.random.nextInt(16) + 8; + int yPos = parameters.decorator.world.getHeightValue(xPos, zPos) - (parameters.random.nextInt(2) + 2); + if (parameters.random.nextInt(10) == 0) { + yPos -= parameters.random.nextInt(10) + 30; + } + if (parameters.random.nextInt(512) != 0) continue; + Random lRand = parameters.chunk.getChunkRandom(75644760L); + new WorldFeatureLabyrinth().generate(parameters.decorator.world, lRand, xPos, yPos, zPos); + } + return null; + } + + /**Vanilla random fluid generation code, takes two custom parameters (int)Chances and (int)BlockID + * @param parameters Parameters Container + * @return null + */ + public static Void generateRandomFluid(Parameters parameters){ + int x = parameters.chunk.xPosition * 16; + int z = parameters.chunk.zPosition * 16; + int chances = (int) parameters.customParameters[0]; + int fluidId = (int) parameters.customParameters[1]; + for (int i = 0; i < chances; ++i) { + int blockX = x + parameters.random.nextInt(16) + 8; + int blockY = parameters.decorator.minY + parameters.random.nextInt(parameters.random.nextInt(parameters.decorator.rangeY - 8) + 8); + int blockZ = z + parameters.random.nextInt(16) + 8; + new WorldFeatureLiquid(fluidId).generate(parameters.decorator.world, parameters.random, blockX, blockY, blockZ); + } + return null; + } + + /**Vanilla lava lake generation code + * @param parameters Parameters Container + * @return null + */ + @Nullable + public static Void generateLavaLakeFeature(Parameters parameters){ + int x = parameters.chunk.xPosition * 16; + int z = parameters.chunk.zPosition * 16; + if (parameters.random.nextInt(32) == 0) { + int xf = x + parameters.random.nextInt(16) + 8; + int yf = parameters.decorator.minY + parameters.random.nextInt(parameters.decorator.rangeY); + int zf = z + parameters.random.nextInt(16) + 8; + if (yf < parameters.decorator.minY + parameters.decorator.rangeY / 2 || parameters.random.nextInt(10) == 0) { + new WorldFeatureLake(Block.fluidLavaStill.id).generate(parameters.decorator.world, parameters.random, xf, yf, zf); + } + } + return null; + } + /**Vanilla obsidian lava lake generation code + * @param parameters Parameters Container + * @return null + */ + @Nullable + public static Void generateObsidianLakeFeature(Parameters parameters){ + int x = parameters.chunk.xPosition * 16; + int z = parameters.chunk.zPosition * 16; + if (parameters.random.nextInt(16) == 0) { + int j1 = x + parameters.random.nextInt(16) + 8; + int i5 = parameters.decorator.minY + parameters.random.nextInt(parameters.decorator.rangeY - 16) + 8; + int j8 = z + parameters.random.nextInt(16) + 8; + if (i5 < parameters.decorator.minY + parameters.decorator.rangeY / 2 || parameters.random.nextInt(10) == 0) { + if (parameters.random.nextInt(4) == 0) { + new WorldFeatureLake(Block.obsidian.id).generate(parameters.decorator.world, parameters.random, j1, i5, j8); + } else { + new WorldFeatureLake(Block.fluidLavaStill.id).generate(parameters.decorator.world, parameters.random, j1, i5, j8); + } + } + } + return null; + } + + /**Vanilla tree feature generator + * @param parameters Parameters Container + * @return Tree feature as specified by Biome#getRandomWorldGenForTrees + */ + public static WorldFeature getTreeFeature(Parameters parameters){ + boolean hasLeaves = parameters.random.nextInt(hellConfig.invLeavesProbability) == 0; + WorldFeature tree = parameters.random.nextInt(10) == 0 ? new WorldFeatureTreeFancy(hasLeaves ? Block.leavesOak.id : 0, Block.logOak.id) : new WorldFeatureTree(hasLeaves ? Block.leavesOak.id : 0, Block.logOak.id, 4); + tree.func_517_a(1.0, 1.0, 1.0); + return tree; + } + + /**Vanilla tree density + * @param parameters Parameters Container + * @return treeDensityOverride if applicable, otherwise returns the biome's tree density from OverworldConfig's tree density hashmap + */ + public static Integer getTreeDensity(Parameters parameters){ + int x = parameters.chunk.xPosition * 16; + int z = parameters.chunk.zPosition * 16; + double d = 0.5; + ChunkDecoratorOverworldHellAPI decoratorHell = (ChunkDecoratorOverworldHellAPI) parameters.decorator; + int treeDensity = (int)((decoratorHell.treeDensityNoise.get((double)x * d, (double)z * d) / 8.0 + parameters.random.nextDouble() * 4.0 + 4.0) / 3.0); + if (parameters.random.nextInt(10) == 0) { + ++treeDensity; + } + return treeDensity/2; + } + + /**Vanilla hell tree generator + * @param parameters Parameters Container, takes two custom parameters getTreeFeature function and getTreeDensity function + * @return null + */ + public static Void generateTrees(Parameters parameters){ + int x = parameters.chunk.xPosition * 16; + int z = parameters.chunk.zPosition * 16; + for (int i = 0; i < getTreeDensity(parameters); i++) { + int xf = x + parameters.random.nextInt(16) + 8; + int zf = z + parameters.random.nextInt(16) + 8; + int yf = parameters.decorator.world.getHeightValue(xf, zf); + getTreeFeature(parameters).generate(parameters.decorator.world, parameters.random, xf, yf, zf); + } + return null; + } +} diff --git a/src/main/java/useless/terrainapi/generation/hell/api/ChunkDecoratorOverworldHellAPI.java b/src/main/java/useless/terrainapi/generation/hell/api/ChunkDecoratorOverworldHellAPI.java new file mode 100644 index 0000000..012e5ca --- /dev/null +++ b/src/main/java/useless/terrainapi/generation/hell/api/ChunkDecoratorOverworldHellAPI.java @@ -0,0 +1,106 @@ +package useless.terrainapi.generation.hell.api; + +import net.minecraft.core.world.World; +import net.minecraft.core.world.biome.Biome; +import net.minecraft.core.world.chunk.Chunk; +import net.minecraft.core.world.generate.feature.WorldFeature; +import net.minecraft.core.world.noise.PerlinNoise; +import org.jetbrains.annotations.ApiStatus; +import useless.terrainapi.config.ConfigManager; +import useless.terrainapi.generation.ChunkDecoratorAPI; +import useless.terrainapi.generation.Parameters; +import useless.terrainapi.generation.StructureFeatures; +import useless.terrainapi.generation.hell.HellConfig; +import useless.terrainapi.generation.overworld.OverworldBiomeFeatures; +import useless.terrainapi.generation.overworld.OverworldOreFeatures; +import useless.terrainapi.generation.overworld.OverworldRandomFeatures; + +import java.util.Random; + +public class ChunkDecoratorOverworldHellAPI extends ChunkDecoratorAPI { + public final PerlinNoise treeDensityNoise; + public static HellConfig hellConfig = ConfigManager.getConfig("hell", HellConfig.class); + public static StructureFeatures structureFeatures = new StructureFeatures(); + public static OverworldOreFeatures oreFeatures = new OverworldOreFeatures(hellConfig); + public static OverworldRandomFeatures randomFeatures = new OverworldRandomFeatures(); + public static OverworldBiomeFeatures biomeFeatures = new OverworldBiomeFeatures(); + protected ChunkDecoratorOverworldHellAPI(World world) { + super(world); + this.treeDensityNoise = new PerlinNoise(world.getRandomSeed(), 8, 74); + } + + @Override + @ApiStatus.Internal + public void decorateAPI() { + int xCoord = parameterBase.chunk.xPosition * 16; + int zCoord = parameterBase.chunk.zPosition * 16; + + generateStructures(parameterBase.biome, parameterBase.chunk, parameterBase.random); + generateOreFeatures(parameterBase.biome, xCoord, zCoord, parameterBase.random, parameterBase.chunk); + generateBiomeFeature(parameterBase.biome,xCoord, zCoord, parameterBase.random, parameterBase.chunk); + generateRandomFeatures(parameterBase.biome,xCoord, zCoord, parameterBase.random, parameterBase.chunk); + + if (this.world.getBlockId(xCoord, minY + this.world.getWorldType().getOceanY() - 1, zCoord) == this.world.getWorldType().getOceanBlock()) { + this.world.setBlockWithNotify(xCoord, minY + this.world.getWorldType().getOceanY() - 1, zCoord, this.world.getWorldType().getOceanBlock()); + } + } + @ApiStatus.Internal + public void generateStructures(Biome biome, Chunk chunk, Random random){ + int featureSize = structureFeatures.featureFunctionList.size(); + for (int i = 0; i < featureSize; i++) { + structureFeatures.featureFunctionList.get(i) + .apply(new Parameters(parameterBase, structureFeatures.featureParametersList.get(i))); + } + } + @ApiStatus.Internal + public void generateOreFeatures(Biome biome, int x, int z, Random random, Chunk chunk){ + int featureSize = oreFeatures.featureFunctionsList.size(); + for (int i = 0; i < featureSize; i++) { + WorldFeature feature = oreFeatures.featureFunctionsList.get(i) + .apply(new Parameters(parameterBase, oreFeatures.featureParametersList.get(i))); + + int density = oreFeatures.densityFunctionsList.get(i) + .apply(new Parameters(parameterBase, oreFeatures.densityParametersList.get(i))); + + float rangeModifier = oreFeatures.rangeModifierList.get(i); + generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, random); + } + } + @ApiStatus.Internal + public void generateRandomFeatures(Biome biome, int x, int z, Random random, Chunk chunk){ + int featureSize = randomFeatures.featureFunctionsList.size(); + for (int i = 0; i < featureSize; i++) { + if (random.nextInt(randomFeatures.inverseProbabilityList.get(i)) != 0) {continue;} + WorldFeature feature = randomFeatures.featureFunctionsList.get(i) + .apply(new Parameters(parameterBase, randomFeatures.featureParametersList.get(i))); + + int density = randomFeatures.densityFunctionsList.get(i) + .apply(new Parameters(parameterBase, randomFeatures.densityParametersList.get(i))); + + float rangeModifier = randomFeatures.rangeModifierList.get(i); + if (-1.01 <= rangeModifier && rangeModifier <= -0.99){ + generateWithChancesSurface(feature, density, x, z, 8, 8, random); + } else { + generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); + } + } + } + @ApiStatus.Internal + public void generateBiomeFeature(Biome biome, int x, int z, Random random, Chunk chunk){ + int featureSize = biomeFeatures.featureFunctionsList.size(); + for (int i = 0; i < featureSize; i++) { + WorldFeature feature = biomeFeatures.featureFunctionsList.get(i) + .apply(new Parameters(parameterBase, biomeFeatures.featureParametersList.get(i))); + + int density = biomeFeatures.densityFunctionsList.get(i) + .apply(new Parameters(parameterBase, biomeFeatures.densityParametersList.get(i))); + + float rangeModifier = biomeFeatures.rangeModifierList.get(i); + if (-1.01 <= rangeModifier && rangeModifier <= -0.99){ + generateWithChancesSurface(feature, density, x, z, 8, 8, random); + } else { + generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); + } + } + } +} diff --git a/src/main/java/useless/terrainapi/generation/hell/api/ChunkGeneratorOverworldHellAPI.java b/src/main/java/useless/terrainapi/generation/hell/api/ChunkGeneratorOverworldHellAPI.java new file mode 100644 index 0000000..e2de6e0 --- /dev/null +++ b/src/main/java/useless/terrainapi/generation/hell/api/ChunkGeneratorOverworldHellAPI.java @@ -0,0 +1,13 @@ +package useless.terrainapi.generation.hell.api; + +import net.minecraft.core.world.World; +import net.minecraft.core.world.generate.MapGenCaves; +import net.minecraft.core.world.generate.chunk.perlin.ChunkGeneratorPerlin; +import net.minecraft.core.world.generate.chunk.perlin.overworld.SurfaceGeneratorOverworld; +import net.minecraft.core.world.generate.chunk.perlin.overworld.TerrainGeneratorOverworld; + +public class ChunkGeneratorOverworldHellAPI extends ChunkGeneratorPerlin { + public ChunkGeneratorOverworldHellAPI(World world) { + super(world, new ChunkDecoratorOverworldHellAPI(world), new TerrainGeneratorOverworld(world), new SurfaceGeneratorOverworld(world), new MapGenCaves(false)); + } +} diff --git a/src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java b/src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java index 127e597..0fd7a70 100644 --- a/src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java +++ b/src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java @@ -23,35 +23,42 @@ public class ChunkDecoratorNetherAPI extends ChunkDecoratorAPI { public static NetherOreFeatures oreFeatures = new NetherOreFeatures(netherConfig); public static NetherRandomFeatures randomFeatures = new NetherRandomFeatures(); public static NetherBiomeFeatures biomeFeatures = new NetherBiomeFeatures(); - private Parameters parameterBase; protected ChunkDecoratorNetherAPI(World world) { super(world); } @Override - @ApiStatus.Internal public void decorate(Chunk chunk) { int chunkX = chunk.xPosition; int chunkZ = chunk.zPosition; + int xCoord = chunkX * 16; int zCoord = chunkZ * 16; - Random random = new Random((long)chunkX * 341873128712L + (long)chunkZ * 132897987541L); - Random structureRand = new Random((long)chunkX * 341873128712L + (long)chunkZ * 341873128712L); + int yCoord = this.world.getHeightValue(xCoord + 16, zCoord + 16); - Biome biome = this.world.getBlockBiome(xCoord + 16, maxY-1, zCoord + 16); + Biome biome = this.world.getBlockBiome(xCoord + 16, yCoord, zCoord + 16); - BlockSand.fallInstantly = true; + chunkSeed = (long)chunkX * 341873128712L + (long)chunkZ * 132897987541L; + Random random = new Random(chunkSeed); parameterBase = new Parameters(biome, random, chunk, this); - generateStructures(biome, chunk, structureRand); - generateOreFeatures(biome, xCoord, zCoord, random, chunk); - generateBiomeFeature(biome,xCoord, zCoord, random, chunk); - generateRandomFeatures(biome,xCoord, zCoord, random, chunk); - + BlockSand.fallInstantly = true; + decorateAPI(); BlockSand.fallInstantly = false; } + @Override + @ApiStatus.Internal + public void decorateAPI() { + int xCoord = parameterBase.chunk.xPosition * 16; + int zCoord = parameterBase.chunk.zPosition * 16; + generateStructures(parameterBase.biome, parameterBase.chunk, parameterBase.random); + generateOreFeatures(parameterBase.biome, xCoord, zCoord, parameterBase.random, parameterBase.chunk); + generateBiomeFeature(parameterBase.biome,xCoord, zCoord, parameterBase.random, parameterBase.chunk); + generateRandomFeatures(parameterBase.biome,xCoord, zCoord, parameterBase.random, parameterBase.chunk); + } + @ApiStatus.Internal public void generateStructures(Biome biome, Chunk chunk, Random random){ int featureSize = structureFeatures.featureFunctionList.size(); diff --git a/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java index 69ca54e..98d75fd 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java @@ -99,7 +99,7 @@ public static int getStandardBiomesDensity(Parameters parameters){ * @return number of chances per chunk scaled by the oreHeightModifier if in valid biome */ public static int getStandardOreBiomesDensity(Parameters parameters){ - float oreHeightModifier = ((ChunkDecoratorOverworldAPI) parameters.decorator).oreHeightModifier; + float oreHeightModifier = parameters.decorator.oreHeightModifier; int chance = (int) parameters.customParameters[0]; Biome[] biomes = (Biome[]) parameters.customParameters[1]; if (biomes == null) {return chance;} @@ -116,15 +116,14 @@ public static int getStandardOreBiomesDensity(Parameters parameters){ public static Void generateDungeons(Parameters parameters){ int x = parameters.chunk.xPosition * 16; int z = parameters.chunk.zPosition * 16; - ChunkDecoratorOverworldAPI decoratorOverworldAPI = (ChunkDecoratorOverworldAPI) parameters.decorator; - for (int i = 0; i < 8.0f * decoratorOverworldAPI.oreHeightModifier; i++) { + for (int i = 0; i < 8.0f * parameters.decorator.oreHeightModifier; i++) { int xPos = x + parameters.random.nextInt(16) + 8; - int yPos = decoratorOverworldAPI.minY + parameters.random.nextInt(decoratorOverworldAPI.rangeY); + int yPos = parameters.decorator.minY + parameters.random.nextInt(parameters.decorator.rangeY); int zPos = z + parameters.random.nextInt(16) + 8; if (parameters.random.nextInt(2) == 0){ - new WorldFeatureDungeon(Block.brickClay.id, Block.brickClay.id, null).generate(decoratorOverworldAPI.world, parameters.random, xPos, yPos, zPos); + new WorldFeatureDungeon(Block.brickClay.id, Block.brickClay.id, null).generate(parameters.decorator.world, parameters.random, xPos, yPos, zPos); } else { - new WorldFeatureDungeon(Block.cobbleStone.id, Block.cobbleStoneMossy.id, null).generate(decoratorOverworldAPI.world, parameters.random, xPos, yPos, zPos); + new WorldFeatureDungeon(Block.cobbleStone.id, Block.cobbleStoneMossy.id, null).generate(parameters.decorator.world, parameters.random, xPos, yPos, zPos); } } return null; @@ -136,19 +135,18 @@ public static Void generateDungeons(Parameters parameters){ */ @Nullable public static Void generateLabyrinths(Parameters parameters){ - ChunkDecoratorOverworldAPI decorator = (ChunkDecoratorOverworldAPI) parameters.decorator; int x = parameters.chunk.xPosition * 16; int z = parameters.chunk.zPosition * 16; for (int i = 0; i < 1; ++i) { int xPos = x + parameters.random.nextInt(16) + 8; int zPos = z + parameters.random.nextInt(16) + 8; - int yPos = decorator.world.getHeightValue(xPos, zPos) - (parameters.random.nextInt(2) + 2); + int yPos = parameters.decorator.world.getHeightValue(xPos, zPos) - (parameters.random.nextInt(2) + 2); if (parameters.random.nextInt(5) == 0) { yPos -= parameters.random.nextInt(10) + 30; } if (parameters.random.nextInt(700) != 0) continue; Random lRand = parameters.chunk.getChunkRandom(75644760L); - new WorldFeatureLabyrinth().generate(decorator.world, lRand, xPos, yPos, zPos); + new WorldFeatureLabyrinth().generate(parameters.decorator.world, lRand, xPos, yPos, zPos); } return null; } @@ -161,27 +159,26 @@ public static Void generateSwamp(Parameters parameters){ if (parameters.biome != Biomes.OVERWORLD_SWAMPLAND) return null; int x = parameters.chunk.xPosition * 16; int z = parameters.chunk.zPosition * 16; - ChunkDecoratorOverworldAPI decorator = (ChunkDecoratorOverworldAPI) parameters.decorator; - Random swampRand = new Random(decorator.chunkSeed); + Random swampRand = new Random(parameters.decorator.chunkSeed); for (int dx = 0; dx < 16; ++dx) { for (int dz = 0; dz < 16; ++dz) { if (!(swampRand.nextFloat() < 0.5f)) continue; - int topBlock = decorator.world.getHeightValue(x + dx, z + dz); - int id = decorator.world.getBlockId(x + dx, topBlock - 1, z + dz); + int topBlock = parameters.decorator.world.getHeightValue(x + dx, z + dz); + int id = parameters.decorator.world.getBlockId(x + dx, topBlock - 1, z + dz); if (id != Block.grass.id) continue; - int posXId = decorator.world.getBlockId(x + dx + 1, topBlock - 1, z + dz); + int posXId = parameters.decorator.world.getBlockId(x + dx + 1, topBlock - 1, z + dz); if (posXId == 0) continue; - int negXId = decorator.world.getBlockId(x + dx - 1, topBlock - 1, z + dz); + int negXId = parameters.decorator.world.getBlockId(x + dx - 1, topBlock - 1, z + dz); if (negXId == 0) continue; - int posZId = decorator.world.getBlockId(x + dx, topBlock - 1, z + dz + 1); + int posZId = parameters.decorator.world.getBlockId(x + dx, topBlock - 1, z + dz + 1); if (posZId == 0) continue; - int negZId = decorator.world.getBlockId(x + dx, topBlock - 1, z + dz - 1); + int negZId = parameters.decorator.world.getBlockId(x + dx, topBlock - 1, z + dz - 1); if (negZId == 0) continue; - int negYId = decorator.world.getBlockId(x + dx, topBlock - 2, z + dz); + int negYId = parameters.decorator.world.getBlockId(x + dx, topBlock - 2, z + dz); if (negYId == 0) continue; if ((!Block.blocksList[posXId].blockMaterial.isSolid() && Block.blocksList[posXId].blockMaterial != Material.water) @@ -189,8 +186,8 @@ public static Void generateSwamp(Parameters parameters){ || (!Block.blocksList[posZId].blockMaterial.isSolid() && Block.blocksList[posZId].blockMaterial != Material.water) || (!Block.blocksList[negZId].blockMaterial.isSolid() && Block.blocksList[negZId].blockMaterial != Material.water) || !Block.blocksList[negYId].blockMaterial.isSolid()) continue; - decorator.world.setBlock(x + dx, topBlock - 1, z + dz, Block.fluidWaterStill.id); - decorator.world.setBlock(x + dx, topBlock, z + dz, 0); + parameters.decorator.world.setBlock(x + dx, topBlock - 1, z + dz, Block.fluidWaterStill.id); + parameters.decorator.world.setBlock(x + dx, topBlock, z + dz, 0); } } return null; @@ -205,17 +202,15 @@ public static Void generateLakeFeature(Parameters parameters){ int x = parameters.chunk.xPosition * 16; int z = parameters.chunk.zPosition * 16; - ChunkDecoratorOverworldAPI decorator = (ChunkDecoratorOverworldAPI) parameters.decorator; - if (lakeChance != 0 && parameters.random.nextInt(lakeChance) == 0) { int fluid = Block.fluidWaterStill.id; if (parameters.biome.hasSurfaceSnow()) { fluid = Block.ice.id; } - int i1 = x + parameters.random.nextInt(16) + 8; - int l4 = decorator.minY + parameters.random.nextInt(decorator.rangeY); - int i8 = z + parameters.random.nextInt(16) + 8; - new WorldFeatureLake(fluid).generate(decorator.world, parameters.random, i1, l4, i8); + int xf = x + parameters.random.nextInt(16) + 8; + int yf = parameters.decorator.minY + parameters.random.nextInt(parameters.decorator.rangeY); + int zf = z + parameters.random.nextInt(16) + 8; + new WorldFeatureLake(fluid).generate(parameters.decorator.world, parameters.random, xf, yf, zf); } return null; } @@ -227,15 +222,47 @@ public static Void generateLakeFeature(Parameters parameters){ public static Void generateLavaLakeFeature(Parameters parameters){ int x = parameters.chunk.xPosition * 16; int z = parameters.chunk.zPosition * 16; - ChunkDecoratorOverworldAPI decorator = (ChunkDecoratorOverworldAPI) parameters.decorator; if (parameters.random.nextInt(8) == 0) { int xf = x + parameters.random.nextInt(16) + 8; - int yf = decorator.minY + parameters.random.nextInt(parameters.random.nextInt(decorator.rangeY - decorator.rangeY / 16) + decorator.rangeY / 16); + int yf = parameters.decorator.minY + parameters.random.nextInt(parameters.random.nextInt(parameters.decorator.rangeY - parameters.decorator.rangeY / 16) + parameters.decorator.rangeY / 16); int zf = z + parameters.random.nextInt(16) + 8; - if (yf < decorator.minY + decorator.rangeY / 2 || parameters.random.nextInt(10) == 0) { - new WorldFeatureLake(Block.fluidLavaStill.id).generate(decorator.world, parameters.random, xf, yf, zf); + if (yf < parameters.decorator.minY + parameters.decorator.rangeY / 2 || parameters.random.nextInt(10) == 0) { + new WorldFeatureLake(Block.fluidLavaStill.id).generate(parameters.decorator.world, parameters.random, xf, yf, zf); } } return null; } + /**Vanilla random fluid generation code, takes two custom parameters (int)Chances and (int)BlockID + * @param parameters Parameters Container + * @return null + */ + public static Void generateRandomFluid(Parameters parameters){ + int x = parameters.chunk.xPosition * 16; + int z = parameters.chunk.zPosition * 16; + int chances = (int) parameters.customParameters[0]; + int fluidId = (int) parameters.customParameters[1]; + for (int i = 0; i < chances; ++i) { + int blockX = x + parameters.random.nextInt(16) + 8; + int blockY = parameters.decorator.minY + parameters.random.nextInt(parameters.random.nextInt(parameters.decorator.rangeY - 8) + 8); + int blockZ = z + parameters.random.nextInt(16) + 8; + new WorldFeatureLiquid(fluidId).generate(parameters.decorator.world, parameters.random, blockX, blockY, blockZ); + } + return null; + } + + /**Vanilla tree generator + * @param parameters Parameters Container, takes two custom parameters getTreeFeature function and getTreeDensity function + * @return null + */ + public static Void generateTrees(Parameters parameters){ + int x = parameters.chunk.xPosition * 16; + int z = parameters.chunk.zPosition * 16; + for (int i = 0; i < getTreeDensity(parameters); i++) { + int xf = x + parameters.random.nextInt(16) + 8; + int zf = z + parameters.random.nextInt(16) + 8; + int yf = parameters.decorator.world.getHeightValue(xf, zf); + getTreeFeature(parameters).generate(parameters.decorator.world, parameters.random, xf, yf, zf); + } + return null; + } } diff --git a/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java b/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java index 20655ba..d3530ed 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java +++ b/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java @@ -1,23 +1,17 @@ package useless.terrainapi.generation.overworld.api; -import net.minecraft.core.block.Block; -import net.minecraft.core.block.BlockSand; -import net.minecraft.core.block.material.Material; import net.minecraft.core.world.World; import net.minecraft.core.world.biome.Biome; -import net.minecraft.core.world.biome.Biomes; import net.minecraft.core.world.chunk.Chunk; import net.minecraft.core.world.generate.feature.WorldFeature; -import net.minecraft.core.world.generate.feature.WorldFeatureLake; -import net.minecraft.core.world.generate.feature.WorldFeatureLiquid; import net.minecraft.core.world.noise.PerlinNoise; import org.jetbrains.annotations.ApiStatus; import useless.terrainapi.config.ConfigManager; -import useless.terrainapi.generation.overworld.OverworldConfig; import useless.terrainapi.generation.ChunkDecoratorAPI; import useless.terrainapi.generation.Parameters; import useless.terrainapi.generation.StructureFeatures; import useless.terrainapi.generation.overworld.OverworldBiomeFeatures; +import useless.terrainapi.generation.overworld.OverworldConfig; import useless.terrainapi.generation.overworld.OverworldOreFeatures; import useless.terrainapi.generation.overworld.OverworldRandomFeatures; @@ -27,13 +21,11 @@ public class ChunkDecoratorOverworldAPI extends ChunkDecoratorAPI { public static OverworldConfig overworldConfig = ConfigManager.getConfig("overworld", OverworldConfig.class); public final PerlinNoise treeDensityNoise; public final int treeDensityOverride; - private Parameters parameterBase; public static StructureFeatures structureFeatures = new StructureFeatures(); public static OverworldOreFeatures oreFeatures = new OverworldOreFeatures(overworldConfig); public static OverworldRandomFeatures randomFeatures = new OverworldRandomFeatures(); public static OverworldBiomeFeatures biomeFeatures = new OverworldBiomeFeatures(); - public long chunkSeed; - protected ChunkDecoratorOverworldAPI(World world, int treeDensityOverride) { + public ChunkDecoratorOverworldAPI(World world, int treeDensityOverride) { super(world); this.treeDensityOverride = treeDensityOverride; this.treeDensityNoise = new PerlinNoise(world.getRandomSeed(), 8, 74); @@ -44,38 +36,14 @@ public ChunkDecoratorOverworldAPI(World world) { } @Override @ApiStatus.Internal - public void decorate(Chunk chunk) { - int chunkX = chunk.xPosition; - int chunkZ = chunk.zPosition; - - int xCoord = chunkX * 16; - int zCoord = chunkZ * 16; - int yCoord = this.world.getHeightValue(xCoord + 16, zCoord + 16); - - Biome biome = this.world.getBlockBiome(xCoord + 16, yCoord, zCoord + 16); - - Random random = new Random(this.world.getRandomSeed()); - long l1 = random.nextLong() / 2L * 2L + 1L; - long l2 = random.nextLong() / 2L * 2L + 1L; - chunkSeed = (long)chunkX * l1 + (long)chunkZ * l2 ^ this.world.getRandomSeed(); - random.setSeed(chunkSeed); - - BlockSand.fallInstantly = true; - - parameterBase = new Parameters(biome, random, chunk, this); - - generateStructures(biome, chunk, random); - generateOreFeatures(biome, xCoord, zCoord, random, chunk); - generateBiomeFeature(biome,xCoord, zCoord, random, chunk); - generateRandomFeatures(biome,xCoord, zCoord, random, chunk); - - generateWithChancesUnderground(new WorldFeatureLiquid(Block.fluidWaterFlowing.id), 50, rangeY, xCoord, zCoord, 8, 8, random); - generateWithChancesUnderground(new WorldFeatureLiquid(Block.fluidLavaFlowing.id), 20, rangeY, xCoord, zCoord, 8, 8, random); - + public void decorateAPI() { + int xCoord = parameterBase.chunk.xPosition * 16; + int zCoord = parameterBase.chunk.zPosition * 16; + generateStructures(parameterBase.biome, parameterBase.chunk, parameterBase.random); + generateOreFeatures(parameterBase.biome, xCoord, zCoord, parameterBase.random, parameterBase.chunk); + generateBiomeFeature(parameterBase.biome,xCoord, zCoord, parameterBase.random, parameterBase.chunk); + generateRandomFeatures(parameterBase.biome,xCoord, zCoord, parameterBase.random, parameterBase.chunk); freezeSurface(xCoord, zCoord); - - BlockSand.fallInstantly = false; - } @ApiStatus.Internal public void generateStructures(Biome biome, Chunk chunk, Random random){ diff --git a/src/main/java/useless/terrainapi/generation/paradise/api/ChunkGeneratorParadiseAPI.java b/src/main/java/useless/terrainapi/generation/paradise/api/ChunkGeneratorParadiseAPI.java new file mode 100644 index 0000000..5c704e2 --- /dev/null +++ b/src/main/java/useless/terrainapi/generation/paradise/api/ChunkGeneratorParadiseAPI.java @@ -0,0 +1,15 @@ +package useless.terrainapi.generation.paradise.api; + +import net.minecraft.core.world.World; +import net.minecraft.core.world.generate.MapGenCaves; +import net.minecraft.core.world.generate.chunk.perlin.ChunkGeneratorPerlin; +import net.minecraft.core.world.generate.chunk.perlin.overworld.SurfaceGeneratorOverworld; +import net.minecraft.core.world.generate.chunk.perlin.paradise.TerrainGeneratorParadise; +import useless.terrainapi.generation.overworld.api.ChunkDecoratorOverworldAPI; + +public class ChunkGeneratorParadiseAPI + extends ChunkGeneratorPerlin { + public ChunkGeneratorParadiseAPI(World world) { + super(world, new ChunkDecoratorOverworldAPI(world), new TerrainGeneratorParadise(world), new SurfaceGeneratorOverworld(world), new MapGenCaves(false)); + } +} diff --git a/src/main/java/useless/terrainapi/generation/retro/RetroConfig.java b/src/main/java/useless/terrainapi/generation/retro/RetroConfig.java new file mode 100644 index 0000000..e52c4bc --- /dev/null +++ b/src/main/java/useless/terrainapi/generation/retro/RetroConfig.java @@ -0,0 +1,6 @@ +package useless.terrainapi.generation.retro; + +import useless.terrainapi.config.OreConfig; + +public class RetroConfig extends OreConfig { +} diff --git a/src/main/java/useless/terrainapi/generation/retro/RetroFunctions.java b/src/main/java/useless/terrainapi/generation/retro/RetroFunctions.java new file mode 100644 index 0000000..229275d --- /dev/null +++ b/src/main/java/useless/terrainapi/generation/retro/RetroFunctions.java @@ -0,0 +1,77 @@ +package useless.terrainapi.generation.retro; + +import net.minecraft.core.block.Block; +import net.minecraft.core.world.generate.feature.WorldFeature; +import net.minecraft.core.world.generate.feature.WorldFeatureDungeon; +import net.minecraft.core.world.generate.feature.tree.WorldFeatureTree; +import net.minecraft.core.world.generate.feature.tree.WorldFeatureTreeFancy; +import useless.terrainapi.generation.Parameters; +import useless.terrainapi.generation.retro.api.ChunkDecoratorRetroAPI; + +public class RetroFunctions { + public static RetroConfig retroConfig = ChunkDecoratorRetroAPI.retroConfig; + + /**Vanilla dungeon generation code + * @param parameters Parameters Container + * @return null + */ + public static Void generateDungeon(Parameters parameters){ + int x = parameters.chunk.xPosition * 16; + int z = parameters.chunk.zPosition * 16; + for (int i1 = 0; i1 < 8; ++i1) { + int structX = x + parameters.random.nextInt(16) + 8; + int structY = parameters.decorator.minY + parameters.random.nextInt(parameters.decorator.rangeY); + int structZ = z + parameters.random.nextInt(16) + 8; + new WorldFeatureDungeon(Block.cobbleStone.id, Block.cobbleStoneMossy.id, null).generate(parameters.decorator.world, parameters.random, structX, structY, structZ); + } + return null; + } + + /**Vanilla tree feature generator + * @param parameters Parameters Container + * @return Tree feature as specified by Biome#getRandomWorldGenForTrees + */ + public static WorldFeature getTreeFeature(Parameters parameters){ + WorldFeature tree = new WorldFeatureTree(Block.leavesOakRetro.id, Block.logOak.id, 4); + if (parameters.random.nextInt(10) == 0) { + tree = new WorldFeatureTreeFancy(Block.leavesOakRetro.id, Block.logOak.id); + } + tree.func_517_a(1.0, 1.0, 1.0); + return tree; + } + + /**Vanilla tree density + * @param parameters Parameters Container + * @return treeDensityOverride if applicable, otherwise returns the biome's tree density from OverworldConfig's tree density hashmap + */ + public static Integer getTreeDensity(Parameters parameters){ + double d = 0.5; + int x = parameters.chunk.xPosition * 16; + int z = parameters.chunk.zPosition * 16; + ChunkDecoratorRetroAPI decoratorRetro = (ChunkDecoratorRetroAPI) parameters.decorator; + int density = (int)((decoratorRetro.treeDensityNoise.get((double)x * d, (double)z * d) / 8.0 + parameters.random.nextDouble() * 4.0 + 4.0) / 3.0); + if (density < 0) { + density = 0; + } + if (parameters.random.nextInt(10) == 0) { + ++density; + } + return density; + } + + /**Vanilla tree generator + * @param parameters Parameters Container, takes two custom parameters getTreeFeature function and getTreeDensity function + * @return null + */ + public static Void generateTrees(Parameters parameters){ + int x = parameters.chunk.xPosition * 16; + int z = parameters.chunk.zPosition * 16; + for (int i = 0; i < getTreeDensity(parameters); i++) { + int xf = x + parameters.random.nextInt(16) + 8; + int zf = z + parameters.random.nextInt(16) + 8; + int yf = parameters.decorator.world.getHeightValue(xf, zf); + getTreeFeature(parameters).generate(parameters.decorator.world, parameters.random, xf, yf, zf); + } + return null; + } +} diff --git a/src/main/java/useless/terrainapi/generation/retro/api/ChunkDecoratorRetroAPI.java b/src/main/java/useless/terrainapi/generation/retro/api/ChunkDecoratorRetroAPI.java new file mode 100644 index 0000000..b57273f --- /dev/null +++ b/src/main/java/useless/terrainapi/generation/retro/api/ChunkDecoratorRetroAPI.java @@ -0,0 +1,103 @@ +package useless.terrainapi.generation.retro.api; + +import net.minecraft.core.world.World; +import net.minecraft.core.world.biome.Biome; +import net.minecraft.core.world.chunk.Chunk; +import net.minecraft.core.world.generate.feature.WorldFeature; +import net.minecraft.core.world.noise.RetroPerlinNoise; +import org.jetbrains.annotations.ApiStatus; +import useless.terrainapi.config.ConfigManager; +import useless.terrainapi.generation.ChunkDecoratorAPI; +import useless.terrainapi.generation.Parameters; +import useless.terrainapi.generation.StructureFeatures; +import useless.terrainapi.generation.overworld.OverworldBiomeFeatures; +import useless.terrainapi.generation.overworld.OverworldOreFeatures; +import useless.terrainapi.generation.overworld.OverworldRandomFeatures; +import useless.terrainapi.generation.retro.RetroConfig; + +import java.util.Random; + +public class ChunkDecoratorRetroAPI extends ChunkDecoratorAPI { + public static RetroConfig retroConfig = ConfigManager.getConfig("retro", RetroConfig.class); + public final RetroPerlinNoise treeDensityNoise; + public final boolean snowCovered; + public static StructureFeatures structureFeatures = new StructureFeatures(); + public static OverworldOreFeatures oreFeatures = new OverworldOreFeatures(retroConfig); + public static OverworldRandomFeatures randomFeatures = new OverworldRandomFeatures(); + public static OverworldBiomeFeatures biomeFeatures = new OverworldBiomeFeatures(); + protected ChunkDecoratorRetroAPI(World world) { + super(world); + this.treeDensityNoise = new RetroPerlinNoise(world.getRandomSeed(), 8, 74); + this.snowCovered = false; + } + @Override + public void decorateAPI() { + int xCoord = parameterBase.chunk.xPosition * 16; + int zCoord = parameterBase.chunk.zPosition * 16; + generateStructures(parameterBase.biome, parameterBase.chunk, parameterBase.random); + generateOreFeatures(parameterBase.biome, xCoord, zCoord, parameterBase.random, parameterBase.chunk); + generateBiomeFeature(parameterBase.biome,xCoord, zCoord, parameterBase.random, parameterBase.chunk); + generateRandomFeatures(parameterBase.biome,xCoord, zCoord, parameterBase.random, parameterBase.chunk); + freezeSurface(xCoord, zCoord); + } + + @ApiStatus.Internal + public void generateStructures(Biome biome, Chunk chunk, Random random){ + int featureSize = structureFeatures.featureFunctionList.size(); + for (int i = 0; i < featureSize; i++) { + structureFeatures.featureFunctionList.get(i) + .apply(new Parameters(parameterBase, structureFeatures.featureParametersList.get(i))); + } + } + @ApiStatus.Internal + public void generateOreFeatures(Biome biome, int x, int z, Random random, Chunk chunk){ + int featureSize = oreFeatures.featureFunctionsList.size(); + for (int i = 0; i < featureSize; i++) { + WorldFeature feature = oreFeatures.featureFunctionsList.get(i) + .apply(new Parameters(parameterBase, oreFeatures.featureParametersList.get(i))); + + int density = oreFeatures.densityFunctionsList.get(i) + .apply(new Parameters(parameterBase, oreFeatures.densityParametersList.get(i))); + + float rangeModifier = oreFeatures.rangeModifierList.get(i); + generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, random); + } + } + @ApiStatus.Internal + public void generateRandomFeatures(Biome biome, int x, int z, Random random, Chunk chunk){ + int featureSize = randomFeatures.featureFunctionsList.size(); + for (int i = 0; i < featureSize; i++) { + if (random.nextInt(randomFeatures.inverseProbabilityList.get(i)) != 0) {continue;} + WorldFeature feature = randomFeatures.featureFunctionsList.get(i) + .apply(new Parameters(parameterBase, randomFeatures.featureParametersList.get(i))); + + int density = randomFeatures.densityFunctionsList.get(i) + .apply(new Parameters(parameterBase, randomFeatures.densityParametersList.get(i))); + + float rangeModifier = randomFeatures.rangeModifierList.get(i); + if (-1.01 <= rangeModifier && rangeModifier <= -0.99){ + generateWithChancesSurface(feature, density, x, z, 8, 8, random); + } else { + generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); + } + } + } + @ApiStatus.Internal + public void generateBiomeFeature(Biome biome, int x, int z, Random random, Chunk chunk){ + int featureSize = biomeFeatures.featureFunctionsList.size(); + for (int i = 0; i < featureSize; i++) { + WorldFeature feature = biomeFeatures.featureFunctionsList.get(i) + .apply(new Parameters(parameterBase, biomeFeatures.featureParametersList.get(i))); + + int density = biomeFeatures.densityFunctionsList.get(i) + .apply(new Parameters(parameterBase, biomeFeatures.densityParametersList.get(i))); + + float rangeModifier = biomeFeatures.rangeModifierList.get(i); + if (-1.01 <= rangeModifier && rangeModifier <= -0.99){ + generateWithChancesSurface(feature, density, x, z, 8, 8, random); + } else { + generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); + } + } + } +} diff --git a/src/main/java/useless/terrainapi/generation/retro/api/ChunkGeneratorRetroAPI.java b/src/main/java/useless/terrainapi/generation/retro/api/ChunkGeneratorRetroAPI.java new file mode 100644 index 0000000..72609e5 --- /dev/null +++ b/src/main/java/useless/terrainapi/generation/retro/api/ChunkGeneratorRetroAPI.java @@ -0,0 +1,13 @@ +package useless.terrainapi.generation.retro.api; + +import net.minecraft.core.world.World; +import net.minecraft.core.world.generate.MapGenCaves; +import net.minecraft.core.world.generate.chunk.perlin.ChunkGeneratorPerlin; +import net.minecraft.core.world.generate.chunk.perlin.overworld.retro.SurfaceGeneratorOverworldRetro; +import net.minecraft.core.world.generate.chunk.perlin.overworld.retro.TerrainGeneratorOverworldRetro; + +public class ChunkGeneratorRetroAPI extends ChunkGeneratorPerlin { + public ChunkGeneratorRetroAPI(World world) { + super(world, new ChunkDecoratorRetroAPI(world), new TerrainGeneratorOverworldRetro(world), new SurfaceGeneratorOverworldRetro(world), new MapGenCaves(true)); + } +} diff --git a/src/main/java/useless/terrainapi/generation/woods/api/ChunkGeneratorOverworldWoodsAPI.java b/src/main/java/useless/terrainapi/generation/woods/api/ChunkGeneratorOverworldWoodsAPI.java new file mode 100644 index 0000000..bf7ec06 --- /dev/null +++ b/src/main/java/useless/terrainapi/generation/woods/api/ChunkGeneratorOverworldWoodsAPI.java @@ -0,0 +1,14 @@ +package useless.terrainapi.generation.woods.api; + +import net.minecraft.core.world.World; +import net.minecraft.core.world.generate.MapGenCaves; +import net.minecraft.core.world.generate.chunk.perlin.ChunkGeneratorPerlin; +import net.minecraft.core.world.generate.chunk.perlin.overworld.SurfaceGeneratorOverworld; +import net.minecraft.core.world.generate.chunk.perlin.overworld.TerrainGeneratorOverworld; +import useless.terrainapi.generation.overworld.api.ChunkDecoratorOverworldAPI; + +public class ChunkGeneratorOverworldWoodsAPI extends ChunkGeneratorPerlin { + public ChunkGeneratorOverworldWoodsAPI(World world) { + super(world, new ChunkDecoratorOverworldAPI(world, 50), new TerrainGeneratorOverworld(world), new SurfaceGeneratorOverworld(world), new MapGenCaves(false)); + } +} diff --git a/src/main/java/useless/terrainapi/initialization/BaseInitialization.java b/src/main/java/useless/terrainapi/initialization/BaseInitialization.java new file mode 100644 index 0000000..11a171c --- /dev/null +++ b/src/main/java/useless/terrainapi/initialization/BaseInitialization.java @@ -0,0 +1,19 @@ +package useless.terrainapi.initialization; + +public abstract class BaseInitialization { + private boolean hasInitialized = false; + public void init() { + if (hasInitialized) return; + hasInitialized = true; + initValues(); + initStructure(); + initOre(); + initRandom(); + initBiome(); + } + protected abstract void initValues(); + protected abstract void initStructure(); + protected abstract void initOre(); + protected abstract void initRandom(); + protected abstract void initBiome(); +} diff --git a/src/main/java/useless/terrainapi/initialization/TerrainInitialization.java b/src/main/java/useless/terrainapi/initialization/TerrainInitialization.java new file mode 100644 index 0000000..15758c4 --- /dev/null +++ b/src/main/java/useless/terrainapi/initialization/TerrainInitialization.java @@ -0,0 +1,26 @@ +package useless.terrainapi.initialization; + +import useless.terrainapi.TerrainMain; +import useless.terrainapi.api.TerrainAPI; +import useless.terrainapi.initialization.worldtypes.HellInitialization; +import useless.terrainapi.initialization.worldtypes.NetherInitialization; +import useless.terrainapi.initialization.worldtypes.OverworldInitialization; +import useless.terrainapi.initialization.worldtypes.RetroInitialization; + +public class TerrainInitialization implements TerrainAPI { + private static boolean hasInitialized = false; + @Override + public String getModID() { + return TerrainMain.MOD_ID; + } + @Override + public void onInitialize() { + if (hasInitialized) {return;} + hasInitialized = true; + new OverworldInitialization().init(); + new NetherInitialization().init(); + new RetroInitialization().init(); + new HellInitialization().init(); + } +} + diff --git a/src/main/java/useless/terrainapi/initialization/worldtypes/HellInitialization.java b/src/main/java/useless/terrainapi/initialization/worldtypes/HellInitialization.java new file mode 100644 index 0000000..c215c95 --- /dev/null +++ b/src/main/java/useless/terrainapi/initialization/worldtypes/HellInitialization.java @@ -0,0 +1,63 @@ +package useless.terrainapi.initialization.worldtypes; + +import net.minecraft.core.block.Block; +import net.minecraft.core.world.generate.feature.WorldFeatureClay; +import net.minecraft.core.world.generate.feature.WorldFeatureDeadBush; +import useless.terrainapi.TerrainMain; +import useless.terrainapi.generation.StructureFeatures; +import useless.terrainapi.generation.hell.HellConfig; +import useless.terrainapi.generation.hell.HellFunctions; +import useless.terrainapi.generation.hell.api.ChunkDecoratorOverworldHellAPI; +import useless.terrainapi.generation.overworld.OverworldBiomeFeatures; +import useless.terrainapi.generation.overworld.OverworldFunctions; +import useless.terrainapi.generation.overworld.OverworldOreFeatures; +import useless.terrainapi.generation.overworld.OverworldRandomFeatures; +import useless.terrainapi.initialization.BaseInitialization; + +public class HellInitialization extends BaseInitialization { + private static final HellConfig hellConfig = ChunkDecoratorOverworldHellAPI.hellConfig; + public static final StructureFeatures structureFeatures = ChunkDecoratorOverworldHellAPI.structureFeatures; + public static final OverworldOreFeatures oreFeatures = ChunkDecoratorOverworldHellAPI.oreFeatures; + public static final OverworldRandomFeatures randomFeatures = ChunkDecoratorOverworldHellAPI.randomFeatures; + public static final OverworldBiomeFeatures biomeFeatures = ChunkDecoratorOverworldHellAPI.biomeFeatures; + @Override + protected void initValues() { + hellConfig.setOreValues(TerrainMain.MOD_ID, Block.blockClay, 32, 20, 1); + } + + @Override + protected void initStructure() { + structureFeatures.addFeature(HellFunctions::generateLavaLakeFeature, null); + structureFeatures.addFeature(HellFunctions::generateObsidianLakeFeature, null); + structureFeatures.addFeature(HellFunctions::generateRandomFluid, new Object[]{50, Block.fluidWaterFlowing.id}); + structureFeatures.addFeature(OverworldFunctions::generateDungeons, null); + structureFeatures.addFeature(HellFunctions::generateLabyrinths, null); + structureFeatures.addFeature(HellFunctions::generateTrees, null); + structureFeatures.addFeature(OverworldFunctions::generateRandomFluid, new Object[]{5, Block.fluidWaterFlowing.id}); + structureFeatures.addFeature(HellFunctions::generateRandomFluid, new Object[]{20, Block.fluidLavaFlowing.id}); + } + + @Override + protected void initOre() { + String blockKey = Block.blockClay.getKey(); + oreFeatures.addFeature(new WorldFeatureClay(hellConfig.clusterSize.get(blockKey)), hellConfig.chancesPerChunk.get(blockKey), hellConfig.verticalRange.get(blockKey)); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.dirt, 32, 20, 1, false); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.gravel, 32, 10, 1, false); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.oreCoalStone, 16, 20, 1, true); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.oreIronStone, 8, 20, 1f/2, true); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.oreGoldStone, 8, 2, 1f/4, true); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.oreRedstoneStone, 7, 8, 1f/8, true); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.oreDiamondStone, 7, 1, 1f/8,true); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.oreLapisStone, 6, 1, 1f/4, true); + } + + @Override + protected void initRandom() { + + } + + @Override + protected void initBiome() { + biomeFeatures.addFeature(new WorldFeatureDeadBush(Block.deadbush.id), 1, 10, null); + } +} diff --git a/src/main/java/useless/terrainapi/initialization/worldtypes/NetherInitialization.java b/src/main/java/useless/terrainapi/initialization/worldtypes/NetherInitialization.java new file mode 100644 index 0000000..d638754 --- /dev/null +++ b/src/main/java/useless/terrainapi/initialization/worldtypes/NetherInitialization.java @@ -0,0 +1,40 @@ +package useless.terrainapi.initialization.worldtypes; + +import net.minecraft.core.block.Block; +import net.minecraft.core.world.generate.feature.*; +import useless.terrainapi.TerrainMain; +import useless.terrainapi.generation.Parameters; +import useless.terrainapi.generation.nether.NetherFunctions; +import useless.terrainapi.generation.nether.api.ChunkDecoratorNetherAPI; +import useless.terrainapi.initialization.BaseInitialization; + +public class NetherInitialization extends BaseInitialization { + @Override + protected void initValues() { + + } + + @Override + protected void initStructure() { + + } + + @Override + protected void initOre() { + ChunkDecoratorNetherAPI.oreFeatures.addFeature(new WorldFeatureNetherLava(Block.fluidLavaFlowing.id), 8,120/128f); + ChunkDecoratorNetherAPI.oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.oreNethercoalNetherrack, 12, 10, 120/128f, false); + ChunkDecoratorNetherAPI.oreFeatures.addFeature((Parameters x) -> new WorldFeatureFire(), null, NetherFunctions::netherFireDensity, null, 120/128f); + ChunkDecoratorNetherAPI.oreFeatures.addFeature((Parameters x) -> new WorldFeatureGlowstoneA(), null, NetherFunctions::netherFireDensity, null, 120/128f); + ChunkDecoratorNetherAPI.oreFeatures.addFeature(new WorldFeatureGlowstoneB(), 10, 120/128f); + } + + @Override + protected void initRandom() { + ChunkDecoratorNetherAPI.randomFeatures.addFeature(new WorldFeatureLake(Block.fluidLavaStill.id), 8, 120/128f); + } + + @Override + protected void initBiome() { + + } +} diff --git a/src/main/java/useless/terrainapi/initialization/worldtypes/OverworldInitialization.java b/src/main/java/useless/terrainapi/initialization/worldtypes/OverworldInitialization.java new file mode 100644 index 0000000..34d170e --- /dev/null +++ b/src/main/java/useless/terrainapi/initialization/worldtypes/OverworldInitialization.java @@ -0,0 +1,119 @@ +package useless.terrainapi.initialization.worldtypes; + +import net.minecraft.core.block.Block; +import net.minecraft.core.world.biome.Biome; +import net.minecraft.core.world.biome.Biomes; +import net.minecraft.core.world.generate.feature.*; +import useless.terrainapi.TerrainMain; +import useless.terrainapi.generation.Parameters; +import useless.terrainapi.generation.StructureFeatures; +import useless.terrainapi.generation.overworld.*; +import useless.terrainapi.generation.overworld.api.ChunkDecoratorOverworldAPI; +import useless.terrainapi.initialization.BaseInitialization; + +public class OverworldInitialization extends BaseInitialization { + + private static final OverworldConfig overworldConfig = ChunkDecoratorOverworldAPI.overworldConfig; + public static final StructureFeatures structureFeatures = ChunkDecoratorOverworldAPI.structureFeatures; + public static final OverworldOreFeatures oreFeatures = ChunkDecoratorOverworldAPI.oreFeatures; + public static final OverworldRandomFeatures randomFeatures = ChunkDecoratorOverworldAPI.randomFeatures; + public static final OverworldBiomeFeatures biomeFeatures = ChunkDecoratorOverworldAPI.biomeFeatures; + @Override + protected void initValues() { + overworldConfig.setOreValues(TerrainMain.MOD_ID, Block.blockClay, 32, 20, 1f); + + overworldConfig.addGrassDensity(Biomes.OVERWORLD_FOREST, 2); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_MEADOW, 2); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_RAINFOREST, 10); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_DESERT, 5); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_SEASONAL_FOREST, 2); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_TAIGA, 1); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_BOREAL_FOREST, 5); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_PLAINS, 10); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_SWAMPLAND, 4); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_SHRUBLAND, 2); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_OUTBACK_GRASSY, 25); + overworldConfig.addGrassDensity(Biomes.OVERWORLD_BIRCH_FOREST, 10); + + overworldConfig.addFlowerDensity(Biomes.OVERWORLD_SEASONAL_FOREST, 1); + overworldConfig.addFlowerDensity(Biomes.OVERWORLD_MEADOW, 2); + overworldConfig.addFlowerDensity(Biomes.OVERWORLD_BOREAL_FOREST, 2); + overworldConfig.addFlowerDensity(Biomes.OVERWORLD_SHRUBLAND, 1); + + overworldConfig.addYellowFlowerDensity(Biomes.OVERWORLD_FOREST, 2); + overworldConfig.addYellowFlowerDensity(Biomes.OVERWORLD_SWAMPLAND, 2); + overworldConfig.addYellowFlowerDensity(Biomes.OVERWORLD_TAIGA, 2); + overworldConfig.addYellowFlowerDensity(Biomes.OVERWORLD_PLAINS, 3); + overworldConfig.addYellowFlowerDensity(Biomes.OVERWORLD_OUTBACK_GRASSY, 2); + overworldConfig.addYellowFlowerDensity(Biomes.OVERWORLD_OUTBACK, 2); + + overworldConfig.addTreeDensity(Biomes.OVERWORLD_FOREST, 5); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_BIRCH_FOREST, 4); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_RAINFOREST, 10); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_SEASONAL_FOREST, 2); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_TAIGA, 5); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_BOREAL_FOREST, 3); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_DESERT, -1000); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_TUNDRA, -1000); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_PLAINS, -1000); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_SWAMPLAND, 4); + overworldConfig.addTreeDensity(Biomes.OVERWORLD_OUTBACK_GRASSY, 0); + + overworldConfig.addRandomGrassBlock(Biomes.OVERWORLD_RAINFOREST, Block.tallgrassFern); + overworldConfig.addRandomGrassBlock(Biomes.OVERWORLD_SWAMPLAND, Block.tallgrassFern); + overworldConfig.addRandomGrassBlock(Biomes.OVERWORLD_BOREAL_FOREST, Block.tallgrassFern); + overworldConfig.addRandomGrassBlock(Biomes.OVERWORLD_TAIGA, Block.tallgrassFern); + + overworldConfig.addLakeDensity(Biomes.OVERWORLD_SWAMPLAND, 2); + overworldConfig.addLakeDensity(Biomes.OVERWORLD_DESERT, 0); + } + + @Override + protected void initStructure() { + structureFeatures.addFeature(OverworldFunctions::generateSwamp, null); + structureFeatures.addFeature(OverworldFunctions::generateLakeFeature, null); + structureFeatures.addFeature(OverworldFunctions::generateLavaLakeFeature, null); + structureFeatures.addFeature(OverworldFunctions::generateDungeons, null); + structureFeatures.addFeature(OverworldFunctions::generateLabyrinths, null); + structureFeatures.addFeature(OverworldFunctions::generateTrees, null); + structureFeatures.addFeature(OverworldFunctions::generateRandomFluid, new Object[]{50, Block.fluidWaterFlowing.id}); + structureFeatures.addFeature(OverworldFunctions::generateRandomFluid, new Object[]{20, Block.fluidLavaFlowing.id}); + } + + @Override + protected void initOre() { + String currentBlock = Block.blockClay.getKey(); + oreFeatures.addFeature(new WorldFeatureClay(overworldConfig.clusterSize.get(currentBlock)), overworldConfig.chancesPerChunk.get(currentBlock), overworldConfig.verticalRange.get(currentBlock)); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.dirt, 32, 20, 1f, false); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.gravel, 32, 10, 1f, false); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.oreCoalStone, 16, 20, 1f, true); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.oreIronStone, 8, 20, 1/2f, true); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.oreGoldStone, 8, 2, 1/4f, true); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.oreRedstoneStone, 7, 8, 1/8f, true); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.oreDiamondStone, 7, 1, 1/8f, true); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.mossStone, 32, 1, 1/2f, true); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID,Block.oreLapisStone, 6, 1, 1/8f, true); + } + + @Override + protected void initRandom() { + randomFeatures.addFeature(new WorldFeatureFlowers(Block.flowerRed.id), 2, 1); + randomFeatures.addFeature(new WorldFeatureFlowers(Block.mushroomBrown.id), 4, 1); + randomFeatures.addFeature(new WorldFeatureFlowers(Block.mushroomRed.id), 8, 1); + randomFeatures.addFeatureSurface(new WorldFeatureSugarCane(), 5); + randomFeatures.addFeatureSurface(new WorldFeaturePumpkin(), 128); + randomFeatures.addFeatureSurface(new WorldFeatureSponge(), 64); + } + + @Override + protected void initBiome() { + biomeFeatures.addFeatureSurface(new WorldFeatureRichScorchedDirt(10), 1, new Biome[]{Biomes.OVERWORLD_OUTBACK, Biomes.OVERWORLD_OUTBACK_GRASSY}); + biomeFeatures.addFeatureSurface(new WorldFeatureSugarCaneTall(), 1, new Biome[]{Biomes.OVERWORLD_RAINFOREST}); + biomeFeatures.addFeature(OverworldFunctions::flowerTypeCondition, null, (Parameters x) -> overworldConfig.getFlowerDensity(x.biome, 0), null, 1f); + biomeFeatures.addFeature((Parameters x) -> new WorldFeatureFlowers(Block.flowerYellow.id), null, (Parameters x) -> overworldConfig.getYellowFlowerDensity(x.biome, 0), null, 1); + biomeFeatures.addFeature(OverworldFunctions::grassTypeCondition, null, (Parameters x) -> overworldConfig.getGrassDensity(x.biome, 0), null, 1); + biomeFeatures.addFeature(new WorldFeatureSpinifexPatch(), 1, 4, new Biome[]{Biomes.OVERWORLD_OUTBACK}); + biomeFeatures.addFeature(new WorldFeatureDeadBush(Block.deadbush.id), 1, 2, new Biome[]{Biomes.OVERWORLD_DESERT}); + biomeFeatures.addFeature(new WorldFeatureCactus(), 1, 10, new Biome[]{Biomes.OVERWORLD_DESERT}); + } +} diff --git a/src/main/java/useless/terrainapi/initialization/worldtypes/RetroInitialization.java b/src/main/java/useless/terrainapi/initialization/worldtypes/RetroInitialization.java new file mode 100644 index 0000000..05495a0 --- /dev/null +++ b/src/main/java/useless/terrainapi/initialization/worldtypes/RetroInitialization.java @@ -0,0 +1,64 @@ +package useless.terrainapi.initialization.worldtypes; + +import net.minecraft.core.block.Block; +import net.minecraft.core.world.generate.feature.WorldFeatureCactus; +import net.minecraft.core.world.generate.feature.WorldFeatureClay; +import net.minecraft.core.world.generate.feature.WorldFeatureFlowers; +import net.minecraft.core.world.generate.feature.WorldFeatureSugarCane; +import useless.terrainapi.TerrainMain; +import useless.terrainapi.config.OreConfig; +import useless.terrainapi.generation.StructureFeatures; +import useless.terrainapi.generation.overworld.OverworldBiomeFeatures; +import useless.terrainapi.generation.overworld.OverworldFunctions; +import useless.terrainapi.generation.overworld.OverworldOreFeatures; +import useless.terrainapi.generation.overworld.OverworldRandomFeatures; +import useless.terrainapi.generation.retro.RetroFunctions; +import useless.terrainapi.generation.retro.api.ChunkDecoratorRetroAPI; +import useless.terrainapi.initialization.BaseInitialization; + +public class RetroInitialization extends BaseInitialization { + private static final OreConfig retroConfig = ChunkDecoratorRetroAPI.retroConfig; + public static final StructureFeatures structureFeatures = ChunkDecoratorRetroAPI.structureFeatures; + public static final OverworldOreFeatures oreFeatures = ChunkDecoratorRetroAPI.oreFeatures; + public static final OverworldRandomFeatures randomFeatures = ChunkDecoratorRetroAPI.randomFeatures; + public static final OverworldBiomeFeatures biomeFeatures = ChunkDecoratorRetroAPI.biomeFeatures; + @Override + protected void initValues() { + retroConfig.setOreValues(TerrainMain.MOD_ID, Block.blockClay, 32, 10, 1); + } + + @Override + protected void initStructure() { + structureFeatures.addFeature(RetroFunctions::generateDungeon, null); + structureFeatures.addFeature(RetroFunctions::generateTrees, null); + structureFeatures.addFeature(OverworldFunctions::generateRandomFluid, new Object[]{50, Block.fluidWaterFlowing.id}); + structureFeatures.addFeature(OverworldFunctions::generateRandomFluid, new Object[]{20, Block.fluidLavaFlowing.id}); + } + + @Override + protected void initOre() { + String currentBlock = Block.blockClay.getKey(); + oreFeatures.addFeature(new WorldFeatureClay(retroConfig.clusterSize.get(currentBlock)), retroConfig.chancesPerChunk.get(currentBlock), retroConfig.verticalRange.get(currentBlock)); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.dirt, 32, 20, 1, false); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.gravel, 32, 10, 1, false); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.oreCoalStone, 16, 20, 1, true); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.oreIronStone, 8, 20, 1f/2, true); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.oreGoldStone, 8, 2, 1f/4, true); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.oreRedstoneStone, 7, 8, 1f/8, true); + oreFeatures.addManagedOreFeature(TerrainMain.MOD_ID, Block.oreDiamondStone, 7, 1, 1f/8, true); + } + + @Override + protected void initRandom() { + randomFeatures.addFeature(new WorldFeatureFlowers(Block.flowerRed.id), 2, 1); + randomFeatures.addFeature(new WorldFeatureFlowers(Block.mushroomBrown.id), 4, 1); + randomFeatures.addFeature(new WorldFeatureFlowers(Block.mushroomRed.id), 8, 1); + } + + @Override + protected void initBiome() { + biomeFeatures.addFeature(new WorldFeatureFlowers(Block.flowerYellow.id), 1, 2, null); + biomeFeatures.addFeature(new WorldFeatureSugarCane(), 1, 10, null); + biomeFeatures.addFeature(new WorldFeatureCactus(), 1, 1, null); + } +} diff --git a/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeFloatingMixin.java b/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeFloatingMixin.java new file mode 100644 index 0000000..63ae1e4 --- /dev/null +++ b/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeFloatingMixin.java @@ -0,0 +1,17 @@ +package useless.terrainapi.mixin.worldtypes; + +import net.minecraft.core.world.World; +import net.minecraft.core.world.generate.chunk.ChunkGenerator; +import net.minecraft.core.world.type.WorldTypeOverworldFloating; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import useless.terrainapi.generation.floating.api.ChunkGeneratorFloatingAPI; +@Mixin(value = WorldTypeOverworldFloating.class, remap = false) +public class WorldTypeFloatingMixin { + @Inject(method = "createChunkGenerator(Lnet/minecraft/core/world/World;)Lnet/minecraft/core/world/generate/chunk/ChunkGenerator;", at = @At("HEAD"), cancellable = true) + private void customChunkGenerator(World world, CallbackInfoReturnable cir){ + cir.setReturnValue(new ChunkGeneratorFloatingAPI(world)); + } +} diff --git a/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeNetherMixin.java b/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeNetherMixin.java new file mode 100644 index 0000000..ebbd4e4 --- /dev/null +++ b/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeNetherMixin.java @@ -0,0 +1,18 @@ +package useless.terrainapi.mixin.worldtypes; + +import net.minecraft.core.world.World; +import net.minecraft.core.world.generate.chunk.ChunkGenerator; +import net.minecraft.core.world.type.WorldTypeNether; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import useless.terrainapi.generation.nether.api.ChunkGeneratorNetherAPI; + +@Mixin(value = WorldTypeNether.class, remap = false, priority = 999) +public class WorldTypeNetherMixin { + @Inject(method = "createChunkGenerator(Lnet/minecraft/core/world/World;)Lnet/minecraft/core/world/generate/chunk/ChunkGenerator;", at = @At("HEAD"), cancellable = true) + private void customChunkGenerator(World world, CallbackInfoReturnable cir){ + cir.setReturnValue(new ChunkGeneratorNetherAPI(world)); + } +} diff --git a/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeOverworldHellMixin.java b/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeOverworldHellMixin.java new file mode 100644 index 0000000..c522bc1 --- /dev/null +++ b/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeOverworldHellMixin.java @@ -0,0 +1,17 @@ +package useless.terrainapi.mixin.worldtypes; + +import net.minecraft.core.world.World; +import net.minecraft.core.world.generate.chunk.ChunkGenerator; +import net.minecraft.core.world.type.WorldTypeOverworldHell; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import useless.terrainapi.generation.hell.api.ChunkGeneratorOverworldHellAPI; +@Mixin(value = WorldTypeOverworldHell.class, remap = false) +public class WorldTypeOverworldHellMixin { + @Inject(method = "createChunkGenerator(Lnet/minecraft/core/world/World;)Lnet/minecraft/core/world/generate/chunk/ChunkGenerator;", at = @At("HEAD"), cancellable = true) + private void customChunkGenerator(World world, CallbackInfoReturnable cir){ + cir.setReturnValue(new ChunkGeneratorOverworldHellAPI(world)); + } +} diff --git a/src/main/java/useless/terrainapi/mixin/WorldTypeOverworldMixin.java b/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeOverworldMixin.java similarity index 95% rename from src/main/java/useless/terrainapi/mixin/WorldTypeOverworldMixin.java rename to src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeOverworldMixin.java index a84b0bd..8c19c51 100644 --- a/src/main/java/useless/terrainapi/mixin/WorldTypeOverworldMixin.java +++ b/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeOverworldMixin.java @@ -1,4 +1,4 @@ -package useless.terrainapi.mixin; +package useless.terrainapi.mixin.worldtypes; import net.minecraft.core.world.World; import net.minecraft.core.world.generate.chunk.ChunkGenerator; diff --git a/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeOverworldRetroMixin.java b/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeOverworldRetroMixin.java new file mode 100644 index 0000000..4caaa89 --- /dev/null +++ b/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeOverworldRetroMixin.java @@ -0,0 +1,18 @@ +package useless.terrainapi.mixin.worldtypes; + +import net.minecraft.core.world.World; +import net.minecraft.core.world.generate.chunk.ChunkGenerator; +import net.minecraft.core.world.type.WorldTypeOverworldRetro; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import useless.terrainapi.generation.retro.api.ChunkGeneratorRetroAPI; + +@Mixin(value = WorldTypeOverworldRetro.class, remap = false, priority = 999) +public class WorldTypeOverworldRetroMixin { + @Inject(method = "createChunkGenerator(Lnet/minecraft/core/world/World;)Lnet/minecraft/core/world/generate/chunk/ChunkGenerator;", at = @At("HEAD"), cancellable = true) + private void customChunkGenerator(World world, CallbackInfoReturnable cir){ + cir.setReturnValue(new ChunkGeneratorRetroAPI(world)); + } +} diff --git a/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeOverworldWoodsMixin.java b/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeOverworldWoodsMixin.java new file mode 100644 index 0000000..6d9ac46 --- /dev/null +++ b/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeOverworldWoodsMixin.java @@ -0,0 +1,18 @@ +package useless.terrainapi.mixin.worldtypes; + +import net.minecraft.core.world.World; +import net.minecraft.core.world.generate.chunk.ChunkGenerator; +import net.minecraft.core.world.type.WorldTypeOverworldWoods; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import useless.terrainapi.generation.woods.api.ChunkGeneratorOverworldWoodsAPI; + +@Mixin(value = WorldTypeOverworldWoods.class, remap = false) +public class WorldTypeOverworldWoodsMixin { + @Inject(method = "createChunkGenerator(Lnet/minecraft/core/world/World;)Lnet/minecraft/core/world/generate/chunk/ChunkGenerator;", at = @At("HEAD"), cancellable = true) + private void customChunkGenerator(World world, CallbackInfoReturnable cir){ + cir.setReturnValue(new ChunkGeneratorOverworldWoodsAPI(world)); + } +} diff --git a/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeParadiseMixin.java b/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeParadiseMixin.java new file mode 100644 index 0000000..d75e8a3 --- /dev/null +++ b/src/main/java/useless/terrainapi/mixin/worldtypes/WorldTypeParadiseMixin.java @@ -0,0 +1,18 @@ +package useless.terrainapi.mixin.worldtypes; + +import net.minecraft.core.world.World; +import net.minecraft.core.world.generate.chunk.ChunkGenerator; +import net.minecraft.core.world.type.WorldTypeParadise; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import useless.terrainapi.generation.paradise.api.ChunkGeneratorParadiseAPI; + +@Mixin(value = WorldTypeParadise.class, remap = false) +public class WorldTypeParadiseMixin { + @Inject(method = "createChunkGenerator(Lnet/minecraft/core/world/World;)Lnet/minecraft/core/world/generate/chunk/ChunkGenerator;", at = @At("HEAD"), cancellable = true) + private void customChunkGenerator(World world, CallbackInfoReturnable cir){ + cir.setReturnValue(new ChunkGeneratorParadiseAPI(world)); + } +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 76329cd..da7dd01 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -21,7 +21,7 @@ "useless.terrainapi.TerrainMain" ], "terrain-api": [ - "useless.terrainapi.TerrainInitialization" + "useless.terrainapi.initialization.TerrainInitialization" ] }, "mixins": [ diff --git a/src/main/resources/terrainapi.mixins.json b/src/main/resources/terrainapi.mixins.json index e407a34..f9295ef 100644 --- a/src/main/resources/terrainapi.mixins.json +++ b/src/main/resources/terrainapi.mixins.json @@ -6,7 +6,13 @@ "mixins": [ "MinecraftMixin", "MinecraftServerMixin", - "WorldTypeOverworldMixin" + "worldtypes.WorldTypeFloatingMixin", + "worldtypes.WorldTypeNetherMixin", + "worldtypes.WorldTypeOverworldHellMixin", + "worldtypes.WorldTypeOverworldMixin", + "worldtypes.WorldTypeOverworldRetroMixin", + "worldtypes.WorldTypeOverworldWoodsMixin", + "worldtypes.WorldTypeParadiseMixin" ], "client": [ ], From 6b9c6f88b31ab91bbfe86df214e37669b4a02260 Mon Sep 17 00:00:00 2001 From: UselessBullets <80850784+UselessBullets@users.noreply.github.com> Date: Fri, 10 Nov 2023 13:50:29 -0600 Subject: [PATCH 10/13] ReAdded Icon --- src/main/resources/fabric.mod.json | 1 + src/main/resources/icon.png | Bin 0 -> 308115 bytes 2 files changed, 1 insertion(+) create mode 100644 src/main/resources/icon.png diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index da7dd01..27ad50c 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -8,6 +8,7 @@ "authors": [ "Useless" ], + "icon": "icon.png", "contact": { "homepage": "", "sources": "" diff --git a/src/main/resources/icon.png b/src/main/resources/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..01d4fa8fc5925fa81635f04f675d655fa4ab02e9 GIT binary patch literal 308115 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 Date: Mon, 13 Nov 2023 12:27:39 -0600 Subject: [PATCH 11/13] Fixes - Fixed potential Null pointer crash - Ore Overwrite warning only appears when actually overwriting values - Fixed world features not generating per chance - Deprecated genTree func is now using standard world feature + density code --- .../useless/terrainapi/config/OreConfig.java | 9 ++-- .../generation/ChunkDecoratorAPI.java | 44 +++++++++++++++++++ .../generation/hell/HellFunctions.java | 3 +- .../api/ChunkDecoratorOverworldHellAPI.java | 30 ++++++++----- .../nether/api/ChunkDecoratorNetherAPI.java | 30 ++++++++----- .../generation/overworld/OverworldConfig.java | 5 ++- .../overworld/OverworldFunctions.java | 1 + .../api/ChunkDecoratorOverworldAPI.java | 30 ++++++++----- .../generation/retro/RetroFunctions.java | 1 + .../retro/api/ChunkDecoratorRetroAPI.java | 30 ++++++++----- .../worldtypes/HellInitialization.java | 2 +- .../worldtypes/OverworldInitialization.java | 2 +- .../worldtypes/RetroInitialization.java | 2 +- .../useless/terrainapi/util/Utilities.java | 14 ++++++ 14 files changed, 145 insertions(+), 58 deletions(-) diff --git a/src/main/java/useless/terrainapi/config/OreConfig.java b/src/main/java/useless/terrainapi/config/OreConfig.java index e038f5d..41f09cc 100644 --- a/src/main/java/useless/terrainapi/config/OreConfig.java +++ b/src/main/java/useless/terrainapi/config/OreConfig.java @@ -33,7 +33,11 @@ public class OreConfig extends APIConfig { * @param range Value from [0, 1], it's the fraction from the bottom of the world to the surface that the ore can generate */ public void setOreValues(String modID, Block block, int clusterSize, int chances, float range){ - if (this.clusterSize.get(block.getKey()) != null){ + String key = block.getKey(); + if (this.clusterSize.containsKey(key) && this.getConfigOverride()){ + return; + } + if (this.clusterSize.getOrDefault(key, clusterSize) != clusterSize || this.chancesPerChunk.getOrDefault(key, chances) != chances || this.verticalRange.getOrDefault(key, range) != range){ TerrainMain.LOGGER.warn(modID + String.format(" has changed block %s to generate %d blocks with %d chances and a range of %f", block.getKey(), clusterSize, chances, range)); } setOreValues(block, clusterSize, chances, range); @@ -46,9 +50,6 @@ public void setOreValues(String modID, Block block, int clusterSize, int chances */ @ApiStatus.Internal protected void setOreValues(Block block, int clusterSize, int chances, float range){ - if (this.clusterSize.containsKey(block.getKey()) && this.getConfigOverride()){ - return; - } this.clusterSize.put(block.getKey(), clusterSize); this.chancesPerChunk.put(block.getKey(), chances); this.verticalRange.put(block.getKey(), range); diff --git a/src/main/java/useless/terrainapi/generation/ChunkDecoratorAPI.java b/src/main/java/useless/terrainapi/generation/ChunkDecoratorAPI.java index be4b68d..80e9871 100644 --- a/src/main/java/useless/terrainapi/generation/ChunkDecoratorAPI.java +++ b/src/main/java/useless/terrainapi/generation/ChunkDecoratorAPI.java @@ -11,6 +11,7 @@ import org.jetbrains.annotations.ApiStatus; import java.util.Random; +import java.util.function.Function; public abstract class ChunkDecoratorAPI implements ChunkDecorator { public final World world; @@ -62,11 +63,24 @@ public void decorate(Chunk chunk){ public abstract void generateRandomFeatures(Biome biome, int x, int z, Random random, Chunk chunk); @ApiStatus.Internal public abstract void generateBiomeFeature(Biome biome, int x, int z, Random random, Chunk chunk); + /** + * @Deprecated Implementation causes world features to be decided before generating multiple instead of each attempt creating patches of "clone" world features + */ @ApiStatus.Internal + @Deprecated public void generateWithChancesUnderground(WorldFeature worldFeature, float chances, int rangeY, int x, int z, Random random){ generateWithChancesUnderground(worldFeature, chances, rangeY, x, z, 0, 0, random); } @ApiStatus.Internal + public void generateWithChancesUnderground(Function featureFunction, Parameters parameters, float chances, int rangeY, int x, int z, Random random){ + generateWithChancesUnderground(featureFunction, parameters, chances, rangeY, x, z, 0, 0, random); + } + + /** + * @Deprecated Implementation causes world features to be decided before generating multiple instead of each attempt creating patches of "clone" world features + */ + @ApiStatus.Internal + @Deprecated public void generateWithChancesUnderground(WorldFeature worldFeature, float chances, int rangeY, int x, int z, int xOff, int zOff, Random random){ for (int i = 0; i < chances; i++) { int posX = x + random.nextInt(16) + xOff; @@ -76,10 +90,31 @@ public void generateWithChancesUnderground(WorldFeature worldFeature, float chan } } @ApiStatus.Internal + public void generateWithChancesUnderground(Function featureFunction, Parameters parameters, float chances, int rangeY, int x, int z, int xOff, int zOff, Random random){ + for (int i = 0; i < chances; i++) { + int posX = x + random.nextInt(16) + xOff; + int posY = minY + random.nextInt(rangeY); + int posZ = z + random.nextInt(16) + zOff; + featureFunction.apply(parameters).generate(world, random, posX, posY, posZ); + } + } + /** + * @Deprecated Implementation causes world features to be decided before generating multiple instead of each attempt creating patches of "clone" world features + */ + @ApiStatus.Internal + @Deprecated public void generateWithChancesSurface(WorldFeature worldFeature, float chances, int x, int z, Random random){ generateWithChancesSurface(worldFeature, chances, x, z, 0, 0, random); } @ApiStatus.Internal + public void generateWithChancesSurface(Function featureFunction, Parameters parameters, float chances, int x, int z, Random random){ + generateWithChancesSurface(featureFunction, parameters, chances, x, z, 0, 0, random); + } + /** + * @Deprecated Implementation causes world features to be decided before generating multiple instead of each attempt creating patches of "clone" world features + */ + @ApiStatus.Internal + @Deprecated public void generateWithChancesSurface(WorldFeature worldFeature, float chances, int x, int z, int xOff, int zOff, Random random){ for (int i = 0; i < chances; i++) { int posX = x + random.nextInt(16) + xOff; @@ -89,6 +124,15 @@ public void generateWithChancesSurface(WorldFeature worldFeature, float chances, } } @ApiStatus.Internal + public void generateWithChancesSurface(Function featureFunction, Parameters parameters, float chances, int x, int z, int xOff, int zOff, Random random){ + for (int i = 0; i < chances; i++) { + int posX = x + random.nextInt(16) + xOff; + int posZ = z + random.nextInt(16) + zOff; + int posY = this.world.getHeightValue(posX, posZ); + featureFunction.apply(parameters).generate(world, random, posX, posY, posZ); + } + } + @ApiStatus.Internal public void freezeSurface(int x, int z){ int oceanY = this.world.getWorldType().getOceanY(); for (int dx = x + 8; dx < x + 8 + 16; ++dx) { diff --git a/src/main/java/useless/terrainapi/generation/hell/HellFunctions.java b/src/main/java/useless/terrainapi/generation/hell/HellFunctions.java index e505bac..9ebb35f 100644 --- a/src/main/java/useless/terrainapi/generation/hell/HellFunctions.java +++ b/src/main/java/useless/terrainapi/generation/hell/HellFunctions.java @@ -124,9 +124,10 @@ public static Integer getTreeDensity(Parameters parameters){ } /**Vanilla hell tree generator - * @param parameters Parameters Container, takes two custom parameters getTreeFeature function and getTreeDensity function + * @param parameters Parameters Container * @return null */ + @Deprecated public static Void generateTrees(Parameters parameters){ int x = parameters.chunk.xPosition * 16; int z = parameters.chunk.zPosition * 16; diff --git a/src/main/java/useless/terrainapi/generation/hell/api/ChunkDecoratorOverworldHellAPI.java b/src/main/java/useless/terrainapi/generation/hell/api/ChunkDecoratorOverworldHellAPI.java index 012e5ca..3a36605 100644 --- a/src/main/java/useless/terrainapi/generation/hell/api/ChunkDecoratorOverworldHellAPI.java +++ b/src/main/java/useless/terrainapi/generation/hell/api/ChunkDecoratorOverworldHellAPI.java @@ -16,6 +16,7 @@ import useless.terrainapi.generation.overworld.OverworldRandomFeatures; import java.util.Random; +import java.util.function.Function; public class ChunkDecoratorOverworldHellAPI extends ChunkDecoratorAPI { public final PerlinNoise treeDensityNoise; @@ -56,14 +57,13 @@ public void generateStructures(Biome biome, Chunk chunk, Random random){ public void generateOreFeatures(Biome biome, int x, int z, Random random, Chunk chunk){ int featureSize = oreFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { - WorldFeature feature = oreFeatures.featureFunctionsList.get(i) - .apply(new Parameters(parameterBase, oreFeatures.featureParametersList.get(i))); - int density = oreFeatures.densityFunctionsList.get(i) .apply(new Parameters(parameterBase, oreFeatures.densityParametersList.get(i))); float rangeModifier = oreFeatures.rangeModifierList.get(i); - generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, random); + generateWithChancesUnderground(oreFeatures.featureFunctionsList.get(i), + new Parameters(parameterBase, oreFeatures.featureParametersList.get(i)), + density, (int) (rangeModifier * rangeY), x, z, random); } } @ApiStatus.Internal @@ -71,17 +71,20 @@ public void generateRandomFeatures(Biome biome, int x, int z, Random random, Chu int featureSize = randomFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { if (random.nextInt(randomFeatures.inverseProbabilityList.get(i)) != 0) {continue;} - WorldFeature feature = randomFeatures.featureFunctionsList.get(i) - .apply(new Parameters(parameterBase, randomFeatures.featureParametersList.get(i))); + Function featureFunction = randomFeatures.featureFunctionsList.get(i); int density = randomFeatures.densityFunctionsList.get(i) .apply(new Parameters(parameterBase, randomFeatures.densityParametersList.get(i))); float rangeModifier = randomFeatures.rangeModifierList.get(i); if (-1.01 <= rangeModifier && rangeModifier <= -0.99){ - generateWithChancesSurface(feature, density, x, z, 8, 8, random); + generateWithChancesSurface(featureFunction, + new Parameters(parameterBase, randomFeatures.featureParametersList.get(i)), + density, x, z, 8, 8, random); } else { - generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); + generateWithChancesUnderground(featureFunction, + new Parameters(parameterBase, randomFeatures.featureParametersList.get(i)), + density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); } } } @@ -89,17 +92,20 @@ public void generateRandomFeatures(Biome biome, int x, int z, Random random, Chu public void generateBiomeFeature(Biome biome, int x, int z, Random random, Chunk chunk){ int featureSize = biomeFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { - WorldFeature feature = biomeFeatures.featureFunctionsList.get(i) - .apply(new Parameters(parameterBase, biomeFeatures.featureParametersList.get(i))); + Function featureFunction = biomeFeatures.featureFunctionsList.get(i); int density = biomeFeatures.densityFunctionsList.get(i) .apply(new Parameters(parameterBase, biomeFeatures.densityParametersList.get(i))); float rangeModifier = biomeFeatures.rangeModifierList.get(i); if (-1.01 <= rangeModifier && rangeModifier <= -0.99){ - generateWithChancesSurface(feature, density, x, z, 8, 8, random); + generateWithChancesSurface(featureFunction, + new Parameters(parameterBase, biomeFeatures.featureParametersList.get(i)), + density, x, z, 8, 8, random); } else { - generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); + generateWithChancesUnderground(featureFunction, + new Parameters(parameterBase, biomeFeatures.featureParametersList.get(i)), + density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); } } } diff --git a/src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java b/src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java index 0fd7a70..32ed41a 100644 --- a/src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java +++ b/src/main/java/useless/terrainapi/generation/nether/api/ChunkDecoratorNetherAPI.java @@ -16,6 +16,7 @@ import useless.terrainapi.generation.nether.NetherRandomFeatures; import java.util.Random; +import java.util.function.Function; public class ChunkDecoratorNetherAPI extends ChunkDecoratorAPI { public static NetherConfig netherConfig = ConfigManager.getConfig("nether", NetherConfig.class); @@ -71,14 +72,13 @@ public void generateStructures(Biome biome, Chunk chunk, Random random){ public void generateOreFeatures(Biome biome, int x, int z, Random random, Chunk chunk){ int featureSize = oreFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { - WorldFeature feature = oreFeatures.featureFunctionsList.get(i) - .apply(new Parameters(parameterBase, oreFeatures.featureParametersList.get(i))); - int density = oreFeatures.densityFunctionsList.get(i) .apply(new Parameters(parameterBase, oreFeatures.densityParametersList.get(i))); float rangeModifier = oreFeatures.rangeModifierList.get(i); - generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, random); + generateWithChancesUnderground(oreFeatures.featureFunctionsList.get(i), + new Parameters(parameterBase, oreFeatures.featureParametersList.get(i)), + density, (int) (rangeModifier * rangeY), x, z, random); } } @ApiStatus.Internal @@ -86,17 +86,20 @@ public void generateRandomFeatures(Biome biome, int x, int z, Random random, Chu int featureSize = randomFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { if (random.nextInt(randomFeatures.inverseProbabilityList.get(i)) != 0) {continue;} - WorldFeature feature = randomFeatures.featureFunctionsList.get(i) - .apply(new Parameters(parameterBase, randomFeatures.featureParametersList.get(i))); + Function featureFunction = randomFeatures.featureFunctionsList.get(i); int density = randomFeatures.densityFunctionsList.get(i) .apply(new Parameters(parameterBase, randomFeatures.densityParametersList.get(i))); float rangeModifier = randomFeatures.rangeModifierList.get(i); if (-1.01 <= rangeModifier && rangeModifier <= -0.99){ - generateWithChancesSurface(feature, density, x, z, 8, 8, random); + generateWithChancesSurface(featureFunction, + new Parameters(parameterBase, randomFeatures.featureParametersList.get(i)), + density, x, z, 8, 8, random); } else { - generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); + generateWithChancesUnderground(featureFunction, + new Parameters(parameterBase, randomFeatures.featureParametersList.get(i)), + density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); } } } @@ -104,17 +107,20 @@ public void generateRandomFeatures(Biome biome, int x, int z, Random random, Chu public void generateBiomeFeature(Biome biome, int x, int z, Random random, Chunk chunk){ int featureSize = biomeFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { - WorldFeature feature = biomeFeatures.featureFunctionsList.get(i) - .apply(new Parameters(parameterBase, biomeFeatures.featureParametersList.get(i))); + Function featureFunction = biomeFeatures.featureFunctionsList.get(i); int density = biomeFeatures.densityFunctionsList.get(i) .apply(new Parameters(parameterBase, biomeFeatures.densityParametersList.get(i))); float rangeModifier = biomeFeatures.rangeModifierList.get(i); if (-1.01 <= rangeModifier && rangeModifier <= -0.99){ - generateWithChancesSurface(feature, density, x, z, 8, 8, random); + generateWithChancesSurface(featureFunction, + new Parameters(parameterBase, biomeFeatures.featureParametersList.get(i)), + density, x, z, 8, 8, random); } else { - generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); + generateWithChancesUnderground(featureFunction, + new Parameters(parameterBase, biomeFeatures.featureParametersList.get(i)), + density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); } } } diff --git a/src/main/java/useless/terrainapi/generation/overworld/OverworldConfig.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldConfig.java index 7d92965..852967f 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/OverworldConfig.java +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldConfig.java @@ -7,6 +7,7 @@ import net.minecraft.core.world.biome.Biome; import org.jetbrains.annotations.NotNull; import useless.terrainapi.config.OreConfig; +import useless.terrainapi.util.Utilities; import javax.annotation.Nullable; import java.util.HashMap; @@ -40,7 +41,7 @@ public void addRandomGrassBlock(Biome biome, Block block) { */ @Nullable public Block getRandomGrassBlock(Biome biome){ - return Block.getBlockByName(biomeRandomGrassBlock.get(Registries.BIOMES.getKey(biome))); + return Utilities.getBlock(biomeRandomGrassBlock.get(Registries.BIOMES.getKey(biome))); } /** @@ -48,7 +49,7 @@ public Block getRandomGrassBlock(Biome biome){ */ @NotNull public Block getRandomGrassBlock(Biome biome, Block defaultValue){ - Block returnBlock = Block.getBlockByName(biomeRandomGrassBlock.get(Registries.BIOMES.getKey(biome))); + Block returnBlock = Utilities.getBlock(biomeRandomGrassBlock.get(Registries.BIOMES.getKey(biome))); if (returnBlock == null){ returnBlock = defaultValue; } diff --git a/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java b/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java index 98d75fd..41da05c 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java +++ b/src/main/java/useless/terrainapi/generation/overworld/OverworldFunctions.java @@ -254,6 +254,7 @@ public static Void generateRandomFluid(Parameters parameters){ * @param parameters Parameters Container, takes two custom parameters getTreeFeature function and getTreeDensity function * @return null */ + @Deprecated public static Void generateTrees(Parameters parameters){ int x = parameters.chunk.xPosition * 16; int z = parameters.chunk.zPosition * 16; diff --git a/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java b/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java index d3530ed..41e05f8 100644 --- a/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java +++ b/src/main/java/useless/terrainapi/generation/overworld/api/ChunkDecoratorOverworldAPI.java @@ -16,6 +16,7 @@ import useless.terrainapi.generation.overworld.OverworldRandomFeatures; import java.util.Random; +import java.util.function.Function; public class ChunkDecoratorOverworldAPI extends ChunkDecoratorAPI { public static OverworldConfig overworldConfig = ConfigManager.getConfig("overworld", OverworldConfig.class); @@ -57,14 +58,13 @@ public void generateStructures(Biome biome, Chunk chunk, Random random){ public void generateOreFeatures(Biome biome, int x, int z, Random random, Chunk chunk){ int featureSize = oreFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { - WorldFeature feature = oreFeatures.featureFunctionsList.get(i) - .apply(new Parameters(parameterBase, oreFeatures.featureParametersList.get(i))); - int density = oreFeatures.densityFunctionsList.get(i) .apply(new Parameters(parameterBase, oreFeatures.densityParametersList.get(i))); float rangeModifier = oreFeatures.rangeModifierList.get(i); - generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, random); + generateWithChancesUnderground(oreFeatures.featureFunctionsList.get(i), + new Parameters(parameterBase, oreFeatures.featureParametersList.get(i)), + density, (int) (rangeModifier * rangeY), x, z, random); } } @ApiStatus.Internal @@ -72,17 +72,20 @@ public void generateRandomFeatures(Biome biome, int x, int z, Random random, Chu int featureSize = randomFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { if (random.nextInt(randomFeatures.inverseProbabilityList.get(i)) != 0) {continue;} - WorldFeature feature = randomFeatures.featureFunctionsList.get(i) - .apply(new Parameters(parameterBase, randomFeatures.featureParametersList.get(i))); + Function featureFunction = randomFeatures.featureFunctionsList.get(i); int density = randomFeatures.densityFunctionsList.get(i) .apply(new Parameters(parameterBase, randomFeatures.densityParametersList.get(i))); float rangeModifier = randomFeatures.rangeModifierList.get(i); if (-1.01 <= rangeModifier && rangeModifier <= -0.99){ - generateWithChancesSurface(feature, density, x, z, 8, 8, random); + generateWithChancesSurface(featureFunction, + new Parameters(parameterBase, randomFeatures.featureParametersList.get(i)), + density, x, z, 8, 8, random); } else { - generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); + generateWithChancesUnderground(featureFunction, + new Parameters(parameterBase, randomFeatures.featureParametersList.get(i)), + density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); } } } @@ -90,17 +93,20 @@ public void generateRandomFeatures(Biome biome, int x, int z, Random random, Chu public void generateBiomeFeature(Biome biome, int x, int z, Random random, Chunk chunk){ int featureSize = biomeFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { - WorldFeature feature = biomeFeatures.featureFunctionsList.get(i) - .apply(new Parameters(parameterBase, biomeFeatures.featureParametersList.get(i))); + Function featureFunction = biomeFeatures.featureFunctionsList.get(i); int density = biomeFeatures.densityFunctionsList.get(i) .apply(new Parameters(parameterBase, biomeFeatures.densityParametersList.get(i))); float rangeModifier = biomeFeatures.rangeModifierList.get(i); if (-1.01 <= rangeModifier && rangeModifier <= -0.99){ - generateWithChancesSurface(feature, density, x, z, 8, 8, random); + generateWithChancesSurface(featureFunction, + new Parameters(parameterBase, biomeFeatures.featureParametersList.get(i)), + density, x, z, 8, 8, random); } else { - generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); + generateWithChancesUnderground(featureFunction, + new Parameters(parameterBase, biomeFeatures.featureParametersList.get(i)), + density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); } } } diff --git a/src/main/java/useless/terrainapi/generation/retro/RetroFunctions.java b/src/main/java/useless/terrainapi/generation/retro/RetroFunctions.java index 229275d..ae97e00 100644 --- a/src/main/java/useless/terrainapi/generation/retro/RetroFunctions.java +++ b/src/main/java/useless/terrainapi/generation/retro/RetroFunctions.java @@ -63,6 +63,7 @@ public static Integer getTreeDensity(Parameters parameters){ * @param parameters Parameters Container, takes two custom parameters getTreeFeature function and getTreeDensity function * @return null */ + @Deprecated public static Void generateTrees(Parameters parameters){ int x = parameters.chunk.xPosition * 16; int z = parameters.chunk.zPosition * 16; diff --git a/src/main/java/useless/terrainapi/generation/retro/api/ChunkDecoratorRetroAPI.java b/src/main/java/useless/terrainapi/generation/retro/api/ChunkDecoratorRetroAPI.java index b57273f..d1c537d 100644 --- a/src/main/java/useless/terrainapi/generation/retro/api/ChunkDecoratorRetroAPI.java +++ b/src/main/java/useless/terrainapi/generation/retro/api/ChunkDecoratorRetroAPI.java @@ -16,6 +16,7 @@ import useless.terrainapi.generation.retro.RetroConfig; import java.util.Random; +import java.util.function.Function; public class ChunkDecoratorRetroAPI extends ChunkDecoratorAPI { public static RetroConfig retroConfig = ConfigManager.getConfig("retro", RetroConfig.class); @@ -53,14 +54,13 @@ public void generateStructures(Biome biome, Chunk chunk, Random random){ public void generateOreFeatures(Biome biome, int x, int z, Random random, Chunk chunk){ int featureSize = oreFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { - WorldFeature feature = oreFeatures.featureFunctionsList.get(i) - .apply(new Parameters(parameterBase, oreFeatures.featureParametersList.get(i))); - int density = oreFeatures.densityFunctionsList.get(i) .apply(new Parameters(parameterBase, oreFeatures.densityParametersList.get(i))); float rangeModifier = oreFeatures.rangeModifierList.get(i); - generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, random); + generateWithChancesUnderground(oreFeatures.featureFunctionsList.get(i), + new Parameters(parameterBase, oreFeatures.featureParametersList.get(i)), + density, (int) (rangeModifier * rangeY), x, z, random); } } @ApiStatus.Internal @@ -68,17 +68,20 @@ public void generateRandomFeatures(Biome biome, int x, int z, Random random, Chu int featureSize = randomFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { if (random.nextInt(randomFeatures.inverseProbabilityList.get(i)) != 0) {continue;} - WorldFeature feature = randomFeatures.featureFunctionsList.get(i) - .apply(new Parameters(parameterBase, randomFeatures.featureParametersList.get(i))); + Function featureFunction = randomFeatures.featureFunctionsList.get(i); int density = randomFeatures.densityFunctionsList.get(i) .apply(new Parameters(parameterBase, randomFeatures.densityParametersList.get(i))); float rangeModifier = randomFeatures.rangeModifierList.get(i); if (-1.01 <= rangeModifier && rangeModifier <= -0.99){ - generateWithChancesSurface(feature, density, x, z, 8, 8, random); + generateWithChancesSurface(featureFunction, + new Parameters(parameterBase, randomFeatures.featureParametersList.get(i)), + density, x, z, 8, 8, random); } else { - generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); + generateWithChancesUnderground(featureFunction, + new Parameters(parameterBase, randomFeatures.featureParametersList.get(i)), + density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); } } } @@ -86,17 +89,20 @@ public void generateRandomFeatures(Biome biome, int x, int z, Random random, Chu public void generateBiomeFeature(Biome biome, int x, int z, Random random, Chunk chunk){ int featureSize = biomeFeatures.featureFunctionsList.size(); for (int i = 0; i < featureSize; i++) { - WorldFeature feature = biomeFeatures.featureFunctionsList.get(i) - .apply(new Parameters(parameterBase, biomeFeatures.featureParametersList.get(i))); + Function featureFunction = biomeFeatures.featureFunctionsList.get(i); int density = biomeFeatures.densityFunctionsList.get(i) .apply(new Parameters(parameterBase, biomeFeatures.densityParametersList.get(i))); float rangeModifier = biomeFeatures.rangeModifierList.get(i); if (-1.01 <= rangeModifier && rangeModifier <= -0.99){ - generateWithChancesSurface(feature, density, x, z, 8, 8, random); + generateWithChancesSurface(featureFunction, + new Parameters(parameterBase, biomeFeatures.featureParametersList.get(i)), + density, x, z, 8, 8, random); } else { - generateWithChancesUnderground(feature, density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); + generateWithChancesUnderground(featureFunction, + new Parameters(parameterBase, biomeFeatures.featureParametersList.get(i)), + density, (int) (rangeModifier * rangeY), x, z, 8, 8, random); } } } diff --git a/src/main/java/useless/terrainapi/initialization/worldtypes/HellInitialization.java b/src/main/java/useless/terrainapi/initialization/worldtypes/HellInitialization.java index c215c95..1e72767 100644 --- a/src/main/java/useless/terrainapi/initialization/worldtypes/HellInitialization.java +++ b/src/main/java/useless/terrainapi/initialization/worldtypes/HellInitialization.java @@ -32,7 +32,6 @@ protected void initStructure() { structureFeatures.addFeature(HellFunctions::generateRandomFluid, new Object[]{50, Block.fluidWaterFlowing.id}); structureFeatures.addFeature(OverworldFunctions::generateDungeons, null); structureFeatures.addFeature(HellFunctions::generateLabyrinths, null); - structureFeatures.addFeature(HellFunctions::generateTrees, null); structureFeatures.addFeature(OverworldFunctions::generateRandomFluid, new Object[]{5, Block.fluidWaterFlowing.id}); structureFeatures.addFeature(HellFunctions::generateRandomFluid, new Object[]{20, Block.fluidLavaFlowing.id}); } @@ -58,6 +57,7 @@ protected void initRandom() { @Override protected void initBiome() { + biomeFeatures.addFeature(HellFunctions::getTreeFeature, null, HellFunctions::getTreeDensity, null, -1f); biomeFeatures.addFeature(new WorldFeatureDeadBush(Block.deadbush.id), 1, 10, null); } } diff --git a/src/main/java/useless/terrainapi/initialization/worldtypes/OverworldInitialization.java b/src/main/java/useless/terrainapi/initialization/worldtypes/OverworldInitialization.java index 34d170e..68f77c0 100644 --- a/src/main/java/useless/terrainapi/initialization/worldtypes/OverworldInitialization.java +++ b/src/main/java/useless/terrainapi/initialization/worldtypes/OverworldInitialization.java @@ -75,7 +75,6 @@ protected void initStructure() { structureFeatures.addFeature(OverworldFunctions::generateLavaLakeFeature, null); structureFeatures.addFeature(OverworldFunctions::generateDungeons, null); structureFeatures.addFeature(OverworldFunctions::generateLabyrinths, null); - structureFeatures.addFeature(OverworldFunctions::generateTrees, null); structureFeatures.addFeature(OverworldFunctions::generateRandomFluid, new Object[]{50, Block.fluidWaterFlowing.id}); structureFeatures.addFeature(OverworldFunctions::generateRandomFluid, new Object[]{20, Block.fluidLavaFlowing.id}); } @@ -108,6 +107,7 @@ protected void initRandom() { @Override protected void initBiome() { biomeFeatures.addFeatureSurface(new WorldFeatureRichScorchedDirt(10), 1, new Biome[]{Biomes.OVERWORLD_OUTBACK, Biomes.OVERWORLD_OUTBACK_GRASSY}); + biomeFeatures.addFeature(OverworldFunctions::getTreeFeature, null, OverworldFunctions::getTreeDensity, null, -1f); biomeFeatures.addFeatureSurface(new WorldFeatureSugarCaneTall(), 1, new Biome[]{Biomes.OVERWORLD_RAINFOREST}); biomeFeatures.addFeature(OverworldFunctions::flowerTypeCondition, null, (Parameters x) -> overworldConfig.getFlowerDensity(x.biome, 0), null, 1f); biomeFeatures.addFeature((Parameters x) -> new WorldFeatureFlowers(Block.flowerYellow.id), null, (Parameters x) -> overworldConfig.getYellowFlowerDensity(x.biome, 0), null, 1); diff --git a/src/main/java/useless/terrainapi/initialization/worldtypes/RetroInitialization.java b/src/main/java/useless/terrainapi/initialization/worldtypes/RetroInitialization.java index 05495a0..02f1d59 100644 --- a/src/main/java/useless/terrainapi/initialization/worldtypes/RetroInitialization.java +++ b/src/main/java/useless/terrainapi/initialization/worldtypes/RetroInitialization.java @@ -30,7 +30,6 @@ protected void initValues() { @Override protected void initStructure() { structureFeatures.addFeature(RetroFunctions::generateDungeon, null); - structureFeatures.addFeature(RetroFunctions::generateTrees, null); structureFeatures.addFeature(OverworldFunctions::generateRandomFluid, new Object[]{50, Block.fluidWaterFlowing.id}); structureFeatures.addFeature(OverworldFunctions::generateRandomFluid, new Object[]{20, Block.fluidLavaFlowing.id}); } @@ -57,6 +56,7 @@ protected void initRandom() { @Override protected void initBiome() { + biomeFeatures.addFeature(RetroFunctions::getTreeFeature, null, RetroFunctions::getTreeDensity, null, -1f); biomeFeatures.addFeature(new WorldFeatureFlowers(Block.flowerYellow.id), 1, 2, null); biomeFeatures.addFeature(new WorldFeatureSugarCane(), 1, 10, null); biomeFeatures.addFeature(new WorldFeatureCactus(), 1, 1, null); diff --git a/src/main/java/useless/terrainapi/util/Utilities.java b/src/main/java/useless/terrainapi/util/Utilities.java index 1673bfb..09c2bed 100644 --- a/src/main/java/useless/terrainapi/util/Utilities.java +++ b/src/main/java/useless/terrainapi/util/Utilities.java @@ -1,7 +1,9 @@ package useless.terrainapi.util; +import net.minecraft.core.block.Block; import net.minecraft.core.data.registry.Registries; import net.minecraft.core.world.biome.Biome; +import org.jetbrains.annotations.Nullable; import java.lang.reflect.Array; @@ -53,4 +55,16 @@ public static T[] concatenate(T[] a, T[] b) { return c; } + + /**Finds a block by its block key + * @param key Block Key + * @return Block if Block exists, null otherwise + */ + @Nullable + public static Block getBlock(String key){ + if (key == null){ + return null; + } + return Block.getBlockByName(key); + } } From bd102c32ea87b020bc8b3a141350003f758e46a2 Mon Sep 17 00:00:00 2001 From: UselessBullets <80850784+UselessBullets@users.noreply.github.com> Date: Mon, 13 Nov 2023 12:44:07 -0600 Subject: [PATCH 12/13] TerrainAPI Lock --- src/main/java/useless/terrainapi/TerrainMain.java | 6 ++++++ .../useless/terrainapi/generation/GeneratorFeatures.java | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/main/java/useless/terrainapi/TerrainMain.java b/src/main/java/useless/terrainapi/TerrainMain.java index 1a65483..50f7d8a 100644 --- a/src/main/java/useless/terrainapi/TerrainMain.java +++ b/src/main/java/useless/terrainapi/TerrainMain.java @@ -17,12 +17,17 @@ public class TerrainMain implements ModInitializer { public static final Gson GSON = (new GsonBuilder()).setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create(); public static final String MOD_ID = "terrain-api"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); + /** + * Prevents accidental use of API Features outside the proper initialization environment + */ + public static boolean LOCK_API = true; @Override public void onInitialize() { LOGGER.info("TerrainMain initialized."); } @ApiStatus.Internal public static void loadModules(){ + LOCK_API = false; new TerrainInitialization().onInitialize(); FabricLoader.getInstance().getEntrypoints("terrain-api", TerrainAPI.class).forEach(api -> { // Make sure the method is implemented @@ -33,5 +38,6 @@ public static void loadModules(){ } }); ConfigManager.saveAll(); + LOCK_API = true; } } diff --git a/src/main/java/useless/terrainapi/generation/GeneratorFeatures.java b/src/main/java/useless/terrainapi/generation/GeneratorFeatures.java index 3b02d81..139a324 100644 --- a/src/main/java/useless/terrainapi/generation/GeneratorFeatures.java +++ b/src/main/java/useless/terrainapi/generation/GeneratorFeatures.java @@ -2,6 +2,7 @@ import net.minecraft.core.world.generate.feature.WorldFeature; import org.jetbrains.annotations.ApiStatus; +import useless.terrainapi.TerrainMain; import java.util.ArrayList; import java.util.List; @@ -24,6 +25,9 @@ public class GeneratorFeatures { * @param densityParameters Object[] of additional parameters that will be included with the Parameters object passed into the density function */ public void addFeature(Function featureFunction, Object[] featureParameters, Function densityFunction, Object[] densityParameters){ + if (TerrainMain.LOCK_API){ + throw new RuntimeException("Illegal use of Terrain Initialization outside of the main terrain-api entrypoint loop!!!"); + } featureFunctionsList.add(featureFunction); featureParametersList.add(featureParameters); densityFunctionsList.add(densityFunction); From a09d7565eb5fb70b819d33bb801fb10f8c6b4b17 Mon Sep 17 00:00:00 2001 From: UselessBullets <80850784+UselessBullets@users.noreply.github.com> Date: Mon, 13 Nov 2023 12:46:26 -0600 Subject: [PATCH 13/13] Version Bump --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 70c3487..991e276 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,6 +10,6 @@ loader_version=0.14.19-babric.1-bta halplibe_version=2.7.0 # Mod -mod_version=1.3.0 +mod_version=1.3.1 mod_group=useless mod_name=terrainapi