From 9152678320bb7988c56eb3f1d4f102bd0e14107d Mon Sep 17 00:00:00 2001 From: Vaern Date: Thu, 14 Apr 2022 21:04:06 -0700 Subject: [PATCH] mapgen fundamentals --- src/main/java/com/hbm/lib/HbmWorld.java | 10 +- .../world/worldgen/ComponentNTMFeatures.java | 185 ++++++++++++++++++ .../hbm/world/worldgen/MapGenNTMFeatures.java | 105 ++++++++++ .../hbm/world/worldgen/NTMWorldGenerator.java | 66 +++++++ 4 files changed, 364 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/hbm/world/worldgen/ComponentNTMFeatures.java create mode 100644 src/main/java/com/hbm/world/worldgen/MapGenNTMFeatures.java create mode 100644 src/main/java/com/hbm/world/worldgen/NTMWorldGenerator.java diff --git a/src/main/java/com/hbm/lib/HbmWorld.java b/src/main/java/com/hbm/lib/HbmWorld.java index c749b4b0b..173bfa1e7 100644 --- a/src/main/java/com/hbm/lib/HbmWorld.java +++ b/src/main/java/com/hbm/lib/HbmWorld.java @@ -3,6 +3,9 @@ package com.hbm.lib; import com.hbm.world.test.StructureComponentTest; import com.hbm.world.test.StructureStartTest; import com.hbm.world.test.WorldGenTest; +import com.hbm.world.worldgen.ComponentNTMFeatures; +import com.hbm.world.worldgen.MapGenNTMFeatures; +import com.hbm.world.worldgen.NTMWorldGenerator; import cpw.mods.fml.common.IWorldGenerator; import cpw.mods.fml.common.registry.GameRegistry; @@ -16,10 +19,13 @@ public class HbmWorld { public static void initWorldGen() { - MapGenStructureIO.registerStructure(StructureStartTest.class, "HFR_STRUCTURE"); - MapGenStructureIO.func_143031_a(StructureComponentTest.class, "HFR_COMPONENT"); + //MapGenStructureIO.registerStructure(StructureStartTest.class, "HFR_STRUCTURE"); + //MapGenStructureIO.func_143031_a(StructureComponentTest.class, "HFR_COMPONENT"); + MapGenStructureIO.registerStructure(MapGenNTMFeatures.Start.class, "NTMFeatures"); + ComponentNTMFeatures.registerNTMFeatures(); registerWorldGen(new HbmWorldGen(), 1); + registerWorldGen(new NTMWorldGenerator(), 1); //registerWorldGen(new WorldGenTest(), 1); } diff --git a/src/main/java/com/hbm/world/worldgen/ComponentNTMFeatures.java b/src/main/java/com/hbm/world/worldgen/ComponentNTMFeatures.java new file mode 100644 index 000000000..1b1ef6068 --- /dev/null +++ b/src/main/java/com/hbm/world/worldgen/ComponentNTMFeatures.java @@ -0,0 +1,185 @@ +package com.hbm.world.worldgen; + +import java.util.Random; + +import com.hbm.blocks.ModBlocks; + +import net.minecraft.init.Blocks; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import net.minecraft.world.gen.structure.MapGenStructureIO; +import net.minecraft.world.gen.structure.StructureBoundingBox; +import net.minecraft.world.gen.structure.StructureComponent; + +//Probably one of the more difficult parts. +/** Base component file. For structure generation under 32x32 blocks, as Minecraft generates 2x2 chunks for structures. + * Larger non-procedural structures should be split up into several bounding boxes, which check if they intersect the chunk bounding box currently being loaded. Doing so will prevent + * cascading world generation. See + * TheMasterCaver's advice. */ +public class ComponentNTMFeatures { + + /** Register structures in MapGenStructureIO */ + public static void registerNTMFeatures() { + MapGenStructureIO.func_143031_a(ComponentNTMFeatures.NTMHouse1.class, "NTMHouse1"); + + } + + /** Sandstone Ruin 1 */ + public static class NTMHouse1 extends ComponentNTMFeatures.Feature { + + private static ComponentNTMFeatures.Sandstone RandomSandstone = new ComponentNTMFeatures.Sandstone(); + + /** Constructor for this feature; takes coordinates for bounding box */ + protected NTMHouse1(Random rand, int minX, int minY, int minZ) { + super(rand, minX, minY, minZ, 9, 4, 6); + } + + @Override + protected void func_143012_a(NBTTagCompound nbt) { + super.func_143012_a(nbt); + } + + @Override + protected void func_143011_b(NBTTagCompound nbt) { + super.func_143011_b(nbt); + } + + /** + * Generates structures. + */ + @Override + public boolean addComponentParts(World world, Random rand, StructureBoundingBox box) { + /* + * Places block at current position. Dependent on coordinate mode, i.e. will allow for random rotation + * this.placeBlockAtCurrentPosition(world, block, minX, metadata, x, y, z, box); + * Fills an area with air, self-explanatory. + * this.fillWithAir(world, box, minX, minY, minZ, maxX, maxY, maxZ); + * Fills an area with blocks, self-explanatory. + * this.fillWithBlocks(world, box, minX, minY, minZ, maxX, maxY, maxZ, blockToPlace, blockToReplace, alwaysReplace); + * Fills an area with metadata blocks, self-explanatory. + * this.fillWithMetadataBlocks(world, box, minX, minY, minZ, maxX, maxY, maxZ, blockToPlace, blockPlaceMeta, blockToReplace, replaceBlockMeta, alwaysReplace); + * Fills an area with randomized blocks, self-explanatory. + * this.fillWithRandomizedBlocks(world, box, minX, minY, minZ, maxX, maxY, maxZ, alwaysReplace, rand, StructureComponent.blockSelector); + * (BlockSelector is basically a list of blocks that can be randomly picked, except that it can actually be weighted) + * Replaces any air or water blocks with this block down to a certain y. Useful for foundations + * this.func_151554_b(world, block, metadata, x, fillDownToY, z, box + * Fills an area with blocks randomly - look into randLimit? + * this.randomlyFillWithBlocks(world, box, rand, randLimit, minX, minY, minZ, maxX, maxY, maxZ, blockToPlace, blockToReplace, alwaysReplace); + */ + + //TODO: func_74935_a is suspect. It seems to be necessary to prevent the structure from spawning at y 0, but it also prevents all spawns. + //System.out.println("" + this.boundingBox.minX + ", " + this.boundingBox.minY + ", " + this.boundingBox.minZ); + if(!this.func_74935_a(world, box, this.boundingBox.minY)) { + return false; + } + //System.out.println("Hpos: " + this.hpos + "; minY:" + this.boundingBox.minY); + + for(byte i = 0; i < scatteredFeatureSizeX; i++) { + for(byte j = 0; j < scatteredFeatureSizeZ; j++) { + this.func_151554_b(world, Blocks.sandstone, 0, i, -1, j, box); + } + } + + this.fillWithBlocks(world, box, 0, 0, 0, scatteredFeatureSizeX, 0, scatteredFeatureSizeZ, Blocks.sandstone, Blocks.air, false); + + this.fillWithRandomizedBlocks(world, box, 0, 1, 0, scatteredFeatureSizeX, 3, 0, false, rand, RandomSandstone); + this.fillWithRandomizedBlocks(world, box, 0, 1, 0, 0, 2, scatteredFeatureSizeZ, false, rand, RandomSandstone); + this.fillWithRandomizedBlocks(world, box, 0, 1, scatteredFeatureSizeZ, scatteredFeatureSizeX, 2, 0, false, rand, RandomSandstone); + + //System.out.println("Successful spawn"); + + return true; + } + + } + + static class Sandstone extends StructureComponent.BlockSelector { + + Sandstone() { } + + /** Selects blocks */ + @Override + public void selectBlocks(Random rand, int p_75062_2_, int p_75062_3_, int p_75062_4_, boolean p_75062_5_) { + if(rand.nextFloat() < 0.6F) { + this.field_151562_a = Blocks.sandstone; + } else if (rand.nextFloat() < 0.4F ) { + this.field_151562_a = ModBlocks.reinforced_sand; + } + + this.field_151562_a = Blocks.sand; + } + + } + + abstract static class Feature extends StructureComponent { + /** The size of the bounding box for this feature in the X axis */ + protected int scatteredFeatureSizeX; + /** The size of the bounding box for this feature in the Y axis */ + protected int scatteredFeatureSizeY; + /** The size of the bounding box for this feature in the Z axis */ + protected int scatteredFeatureSizeZ; + /** Average height? */ + protected int hpos = -1; + + + protected Feature(Random rand, int minX, int minY, int minZ, int maxX, int maxY, int maxZ ) { + super(0); + this.scatteredFeatureSizeX = maxX; + this.scatteredFeatureSizeY = maxY; + this.scatteredFeatureSizeZ = maxZ; + this.coordBaseMode = rand.nextInt(4); + + switch(this.coordBaseMode) { + case 0: + case 2: + this.boundingBox = new StructureBoundingBox(minX, minY, minZ, minX + maxX - 1, minY + maxY - 1, minZ + maxZ - 1); + break; + default: + this.boundingBox = new StructureBoundingBox(minX, minY, minZ, minX + maxZ - 1, minY + maxY - 1, minZ + maxX - 1); + } + } + + /** Set to NBT */ + protected void func_143012_a(NBTTagCompound nbt) { + nbt.setInteger("Width", this.scatteredFeatureSizeX); + nbt.setInteger("Height", this.scatteredFeatureSizeY); + nbt.setInteger("Depth", this.scatteredFeatureSizeZ); + nbt.setInteger("HPos", this.hpos); + } + + /** Get from NBT */ + protected void func_143011_b(NBTTagCompound nbt) { + this.scatteredFeatureSizeX = nbt.getInteger("Width"); + this.scatteredFeatureSizeY = nbt.getInteger("Height"); + this.scatteredFeatureSizeZ = nbt.getInteger("Depth"); + this.hpos = nbt.getInteger("HPos"); + } + + protected boolean func_74935_a(World world, StructureBoundingBox box, int y) { + //System.out.println("original: " + hpos); + //System.out.println(y); + + int j = 0; + int k = 0; + + for(int l = this.boundingBox.minZ; l <= this.boundingBox.maxZ; l++) { + for(int i = this.boundingBox.minX; i <= this.boundingBox.maxX; i++) { + if(box.isVecInside(i, y, l)) { + j += Math.max(world.getTopSolidOrLiquidBlock(i, l), world.provider.getAverageGroundLevel()); + k++; + } + } + } + + if(k == 0) + return false; + + this.hpos = j / k; + this.boundingBox.offset(0, this.hpos - this.boundingBox.minY, 0); + //System.out.println("new: " + hpos); + //System.out.println(y); + return true; + } + } + +} diff --git a/src/main/java/com/hbm/world/worldgen/MapGenNTMFeatures.java b/src/main/java/com/hbm/world/worldgen/MapGenNTMFeatures.java new file mode 100644 index 000000000..4c2c89bdf --- /dev/null +++ b/src/main/java/com/hbm/world/worldgen/MapGenNTMFeatures.java @@ -0,0 +1,105 @@ +package com.hbm.world.worldgen; + +import java.util.Iterator; +import java.util.List; +import java.util.Random; + +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeGenBase; +import net.minecraft.world.gen.structure.ComponentScatteredFeaturePieces; +import net.minecraft.world.gen.structure.MapGenStructure; +import net.minecraft.world.gen.structure.StructureStart; +import scala.actors.threadpool.Arrays; + +public class MapGenNTMFeatures extends MapGenStructure { + + private static List biomelist = Arrays.asList(new BiomeGenBase[] {BiomeGenBase.ocean, BiomeGenBase.river, BiomeGenBase.frozenOcean, BiomeGenBase.frozenRiver, BiomeGenBase.deepOcean}); + /** Maximum distance between structures */ + private int maxDistanceBetweenScatteredFeatures; + /** Minimum distance between structures */ + private int minDistanceBetweenScatteredFeatures; + + public MapGenNTMFeatures() { + this.maxDistanceBetweenScatteredFeatures = 16; + this.minDistanceBetweenScatteredFeatures = 6; + } + + /** String ID for this MapGen */ + @Override + public String func_143025_a() { + return "NTMFeatures"; + } + + /** + * Checks if a structure can be spawned at coords, based off of chance and biome + * (Good approach would probably be to only exclude ocean biomes through biomelist and rely on temperature and rainfall instead of biomegenbase, would allow for biomes o' plenty compat) + */ + @Override + protected boolean canSpawnStructureAtCoords(int chunkX, int chunkZ) { + + int k = chunkX; + int l = chunkZ; + + if(chunkX < 0) + chunkX -= this.maxDistanceBetweenScatteredFeatures - 1; + if(chunkZ < 0) + chunkZ -= this.maxDistanceBetweenScatteredFeatures - 1; + + int i1 = chunkX / this.maxDistanceBetweenScatteredFeatures; + int j1 = chunkZ / this.maxDistanceBetweenScatteredFeatures; + Random random = this.worldObj.setRandomSeed(i1, j1, 14357617); + i1 *= this.maxDistanceBetweenScatteredFeatures; + j1 *= this.maxDistanceBetweenScatteredFeatures; + i1 += random.nextInt(this.maxDistanceBetweenScatteredFeatures - this.minDistanceBetweenScatteredFeatures); + j1 += random.nextInt(this.maxDistanceBetweenScatteredFeatures - this.minDistanceBetweenScatteredFeatures); + + if(k == i1 && l == j1) { + BiomeGenBase biomegenbase = this.worldObj.getWorldChunkManager().getBiomeGenAt(k * 16 + 8, l * 16 + 8); + Iterator iterator = biomelist.iterator(); + + while(iterator.hasNext()) { + BiomeGenBase biomegenbase1 = (BiomeGenBase)iterator.next(); + + if(biomegenbase == biomegenbase1) + return false; + } + return true; + } + + return false; + } + + + //StructureStart Methods Class + + /** Returns new StructureStart if structure can be spawned at coords */ + @Override + protected StructureStart getStructureStart(int chunkX, int chunkZ) { + return new MapGenNTMFeatures.Start(this.worldObj, this.rand, chunkX, chunkZ); + } + + public static class Start extends StructureStart { + + public Start(World world, Random rand, int chunkX, int chunkZ) { + super(chunkX, chunkZ); + + BiomeGenBase biomegenbase = world.getBiomeGenForCoords(chunkX * 16 + 8, chunkZ * 16 + 8); + int posY = world.getHeightValue(chunkX * 16 + 8, chunkZ * 16 + 8); + if(posY == 0) + posY = world.getTopSolidOrLiquidBlock(chunkX * 16 + 8, chunkZ * 16 + 8); + + /* + * Probably want to use nextInt() to increase the structures of rarity here. As a fallback, you could have generic stone brick/useless block ruins that will always be chosen if the + * chance/location fails for all other structures. Might not even be necessary, but whatever. + * Rainfall & Temperature Check + */ + + //if(biomegenbase.temperature < 0.1) { + ComponentNTMFeatures.NTMHouse1 house1 = new ComponentNTMFeatures.NTMHouse1(rand, chunkX * 16 + 8, posY, chunkZ * 16 + 8); + this.components.add(house1); + //} + + this.updateBoundingBox(); + } + } +} diff --git a/src/main/java/com/hbm/world/worldgen/NTMWorldGenerator.java b/src/main/java/com/hbm/world/worldgen/NTMWorldGenerator.java new file mode 100644 index 000000000..8685883ef --- /dev/null +++ b/src/main/java/com/hbm/world/worldgen/NTMWorldGenerator.java @@ -0,0 +1,66 @@ +package com.hbm.world.worldgen; + +import java.util.Random; + +import com.hbm.config.GeneralConfig; + +import cpw.mods.fml.common.IWorldGenerator; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import net.minecraft.block.Block; +import net.minecraft.world.World; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraftforge.event.terraingen.ChunkProviderEvent.ReplaceBiomeBlocks; +import net.minecraftforge.event.terraingen.InitMapGenEvent.EventType; +import net.minecraftforge.event.terraingen.PopulateChunkEvent; +import net.minecraftforge.event.terraingen.TerrainGen; + +public class NTMWorldGenerator implements IWorldGenerator { + + private MapGenNTMFeatures NTMFeatureGenerator = new MapGenNTMFeatures(); + + { + NTMFeatureGenerator = (MapGenNTMFeatures) TerrainGen.getModdedMapGen(NTMFeatureGenerator, EventType.CUSTOM); + } + + @Override + public void generate(Random rand, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider) { + + switch (world.provider.dimensionId) { + case -1: + generateNether(world, rand, chunkGenerator, chunkX, chunkZ); break; + case 0: + generateSurface(world, rand, chunkGenerator, chunkX, chunkZ); break; + case 1: + generateEnd(world, rand, chunkGenerator, chunkX, chunkZ); break; + } + } + + private void generateNether(World world, Random rand, IChunkProvider chunkGenerator, int chunkX, int chunkZ) { + // TODO Auto-generated method stub + + } + + private void generateSurface(World world, Random rand, IChunkProvider chunkGenerator, int chunkX, int chunkZ) { + Block[] ablock = new Block[65536]; + + //WorldConfig.enableStructures + /** Spawns structure starts. Utilizes canSpawnStructureAtCoords() + if else checks in Start constructor */ + if(GeneralConfig.enableDungeons) { + this.NTMFeatureGenerator.func_151539_a(chunkGenerator, world, chunkX, chunkZ, ablock); + } + + /** Actually generates structures in a given chunk. */ + if(GeneralConfig.enableDungeons) { + this.NTMFeatureGenerator.generateStructuresInChunk(world, rand, chunkX, chunkZ); + } + } + + private void generateEnd(World world, Random rand, IChunkProvider chunkGenerator, int chunkX, int chunkZ) { + // TODO Auto-generated method stub + + } + + + + +}