Jump to content

Structure Spawning in 1.7.2


SureenInk

Recommended Posts

Problem 1 [solved]

 

Okay, so, I've figured out the basics of structure spawning, but I'm having an issue...I can't seem to figure out a way to make it spawn a very small amount. Right now, it is spawning so much that the structure is spawning inside of itself. Screenshot for clarification: http://i176.photobucket.com/albums/w197/SureenInk/2014-04-24_175633_zps3ac6fa6b.png

 

Also, can anyone help me get the hardened clay to spawn right? Supposedly it has a metadata right now of 14, but it's just spawning normal hardened clay...

world.setBlock(i + 0, j + 17, k + 4, Blocks.hardened_clay, 14, 4);

 

This is the code for my structure spawning (I have it set to 1 because the higher the number, the more it seems to spawn).

 

package craftygirls.core.main;

import java.util.Random;

import net.minecraft.block.Block;
import net.minecraft.world.World;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.gen.feature.WorldGenMinable;
import cpw.mods.fml.common.IWorldGenerator;
import craftygirls.core.events.AliceGenTrees;
import craftygirls.core.events.FreeGenTrees;
import craftygirls.core.events.MaryGenTrees;
import craftygirls.core.events.StefGenTrees;
import craftygirls.core.structures.WorldGenTTSnimCastle;

public class CraftyGirlsWorldGeneration implements IWorldGenerator
{
public void generate(Random random, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider)
{
	switch (world.provider.dimensionId)
	{
	case -1:
		generateNether(world, random, chunkX * 16, chunkZ * 16);
	case 0:
		generateSurface(world, random, chunkX * 16, chunkZ * 16);
	case 1:
		generateEnd(world, random, chunkX * 16, chunkZ * 16);
	}
}

private void generateNether(World world, Random random, int x, int z) {

}

private void generateEnd(World world, Random random, int x, int z)
{

}

private void generateSurface(World world, Random random, int x, int z)
{
	this.addOreSpawn(CraftyGirlsMain.AliceOre, world, random, x, z, 16, 16, 4 + random.nextInt(3), 5, 1, 50);
	this.addOreSpawn(CraftyGirlsMain.StefOre, world, random, x, z, 16, 16, 4 + random.nextInt(3), 5, 1, 50);
	this.addOreSpawn(CraftyGirlsMain.FreeOre, world, random, x, z, 16, 16, 4 + random.nextInt(3), 5, 1, 50);
	this.addOreSpawn(CraftyGirlsMain.MaryOre, world, random, x, z, 16, 16, 4 + random.nextInt(3), 5, 1, 50);

	BiomeGenBase biomeGenBase = world.getWorldChunkManager().getBiomeGenAt(x + 16, z + 16);

	double rand = Math.random();
	System.out.println(rand);
	if (rand > 0.9D){
		for (int td = 0; td < 1; td++) {
			int chunkX = x + random.nextInt(16);
			int chunkY = random.nextInt(150);
			int chunkZ = z + random.nextInt(16);

			new WorldGenTTSnimCastle().generate(world, random, chunkX, chunkY, chunkZ);
		}
	}
	if (biomeGenBase == CraftyGirlsMain.StefBiome) {
	for (int sb = 0; sb < 5; sb++) {
		int chunkX = x + random.nextInt(16);
		int chunkY = random.nextInt(90);
		int chunkZ = z + random.nextInt(16);

		new StefGenTrees(false, 5, 0, 0, false).generate(world, random, chunkX, chunkY, chunkZ);
		}
	}
	if (biomeGenBase == CraftyGirlsMain.MaryBiome) {
		for (int mb = 0; mb < 5; mb++) {
			int chunkX = x + random.nextInt(16);
			int chunkY = random.nextInt(100);
			int chunkZ = z + random.nextInt(16);

			new MaryGenTrees(false, 5, 0, 0, false).generate(world, random, chunkX, chunkY, chunkZ);
		}
	}
	if (biomeGenBase == CraftyGirlsMain.AliceBiome) {
		for (int ab = 0; ab < 5; ab++) {
			int chunkX = x + random.nextInt(16);
			int chunkY = random.nextInt(100);
			int chunkZ = z + random.nextInt(16);

			new AliceGenTrees(false, 5, 0, 0, false).generate(world, random, chunkX, chunkY, chunkZ);
		}
	}
	if (biomeGenBase == CraftyGirlsMain.FreeBiome) {
		for (int fb = 0; fb < 5; fb++) {
			int chunkX = x + random.nextInt(16);
			int chunkY = random.nextInt(100);
			int chunkZ = z + random.nextInt(16);

			new FreeGenTrees(false, 5, 0, 0, false).generate(world, random, chunkX, chunkY, chunkZ);
		}
	}
}

/**
 * Adds an Ore Spawn to Minecraft. Simply register all Ores to spawn with this method in your Generation method in your IWorldGeneration extending Class
 * 
 * @param The Block to spawn
 * @param The World to spawn in
 * @param A Random object for retrieving random positions within the world to spawn the Block
 * @param An int for passing the X-Coordinate for the Generation method
 * @param An int for passing the Z-Coordinate for the Generation method
 * @param An int for setting the maximum X-Coordinate values for spawning on the X-Axis on a Per-Chunk basis
 * @param An int for setting the maximum Z-Coordinate values for spawning on the Z-Axis on a Per-Chunk basis
 * @param An int for setting the maximum size of a vein
 * @param An int for the Number of chances available for the Block to spawn per-chunk
 * @param An int for the minimum Y-Coordinate height at which this block may spawn
 * @param An int for the maximum Y-Coordinate height at which this block may spawn
 **/
public void addOreSpawn(Block block, World world, Random random, int blockXPos, int blockZPos, int maxX, int maxZ, int maxVeinSize, int chancesToSpawn, int minY, int maxY)
{
	assert maxY > minY : "The maximum Y must be greater than the Minimum Y";
	assert maxX > 0 && maxX <= 16 : "addOreSpawn: The Maximum X must be greater than 0 and less than 16";
	assert minY > 0 : "addOreSpawn: The Minimum Y must be greater than 0";
	assert maxY < 256 && maxY > 0 : "addOreSpawn: The Maximum Y must be less than 256 but greater than 0";
	assert maxZ > 0 && maxZ <= 16 : "addOreSpawn: The Maximum Z must be greater than 0 and less than 16";

	int diffBtwnMinMaxY = maxY - minY;
	for (int x = 0; x < chancesToSpawn; x++)
	{
		int posX = blockXPos + random.nextInt(maxX);
		int posY = minY + random.nextInt(diffBtwnMinMaxY);
		int posZ = blockZPos + random.nextInt(maxZ);
		(new WorldGenMinable(block, maxVeinSize)).generate(world, random, posX, posY, posZ);
	}
}
}

 

And this is what I have of the structure spawning code (didn't add in any of the setblocks cause the forum said the post was too big...):

package craftygirls.core.structures;
import java.util.Random;

import net.minecraft.block.Block;
import net.minecraft.init.Blocks;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.WorldGenerator;
import craftygirls.core.main.CraftyGirlsMain;

public class WorldGenTTSnimCastle extends WorldGenerator
{
protected Block[] GetValidSpawnBlocks() {
	return new Block[] {
		Blocks.air,
	};
}

public boolean LocationIsValidSpawn(World world, int i, int j, int k){
	int distanceToAir = 0;
	Block checkID = world.getBlock(i, j, k);

	while (checkID != Blocks.air){
		distanceToAir++;
		checkID = world.getBlock(i, j + distanceToAir, k);
	}

	if (distanceToAir > 3){
		return false;
	}
	j += distanceToAir - 1;

	Block blockID = world.getBlock(i, j, k);
	Block blockIDAbove = world.getBlock(i, j+1, k);
	Block blockIDBelow = world.getBlock(i, j-1, k);
	for (Block x : GetValidSpawnBlocks()){
		if (blockIDAbove != Blocks.air){
			return false;
		}
		if (blockID == x){
			return true;
		}else if (blockID == Blocks.snow && blockIDBelow == x){
			return true;
		}
	}
	return false;
}

public WorldGenTTSnimCastle() { }

public boolean generate(World world, Random rand, int i, int j, int k) {
	//check that each corner is one of the valid spawn blocks
	if(!LocationIsValidSpawn(world, i, j, k) || !LocationIsValidSpawn(world, i + 61, j, k) || !LocationIsValidSpawn(world, i + 61, j, k + 61) || !LocationIsValidSpawn(world, i, j, k + 61))
	{
		return false;
	}

 

 

Problem 2: New problem...I have this coding for my mob spawners

TileEntityMobSpawner ttsnimspawner = (TileEntityMobSpawner)world.getTileEntity(i + 6, j + 11, k + 6);
	ttsnimspawner.func_145881_a().setEntityName("Skeleton");

 

When a second structure spawns in, it seems to error on this code. It works fine when there's one structure, but I flew to a second structure and it errored and crashed. I don't understand why... Also, how would I go about adding loot to the chests I have in my dungeon?

Link to comment
Share on other sites

If I'm interpreting this correctly, couldn't you just reduce its spawn rate by only making it generate X amount of the time? For example, if you wanted it to generate a quarter as much then you could generate a random number between one and four and only have it generate if the number is four? Alternatively, you could make the structure generate a specific block in the dead center of it, and each generation make sure there isn't one of those blocks within X blocks of the new generation (via 3 stacked for loops)

Creator of Metroid Cubed! Power Suits, Beams, Hypermode and more!

width=174 height=100http://i.imgur.com/ghgWmA3.jpg[/img]

Link to comment
Share on other sites

Unfortunately, that's what I tried to do. The random number generates a random number between 0.0 and 1.0. It's set to 0.9 (10% of the time, it's about as low as I can set it). It runs about 32 times per chunk, though...it's almost guaranteed to be set at least once. As for checking for coordinates and such, I don't have the slightest idea how to do that. What I would like to do is make it spawn every 300 blocks (like - 0, 300, 600, 900) then run some random code to then tell it "Okay, at these coordinates run a random number to determine which structure to generate there". I have no idea how to do that, though. I've tried some things, but nothing has worked, so I'm not sure what to do.

Link to comment
Share on other sites

Is this beyond what someone is willing to help with? Cause I really can't find any information on doing this...Again, I'd like to do a sort of "Twilight Forest" thing where the structures spawn in specific locations. Like, maybe every 300 blocks or so (so on like 0,0, then 0,300, and 0,-300, and 300,0, etc.)

Link to comment
Share on other sites

You can check if one number (here: current position) is a multiple of another number (here: your desired spacing of 300 blocks) with the modulo operator. Since the coordinates you pass to generateSurface() are already multiplied by 16 this will only work for spacings that are multiples of 16. E.g.:

private void generateSurface(World world, Random random, int x, int z)
  if ((x % 320 == 0) && (z % 320 ==0)) {
    // set chunkX etc.
    new Castle.generate(world, random, chunkX, chunkY, chunkZ);
  }
}

 

 

If you want it to work for spacings that are not a multiple of 16 then checking whether the current chunk contains a desired position becomes a bit more complicated, and to have it work correctly for coordinates <=0 you either need to handle that case extra or use a division that "rounds down".  The code below uses the latter.

 

So, for e.g. x=0, 200, 400, 600, ... and z=0, 100, 200, 300, ...:

 

/**
* 
* @param n
* @param d
* @return n/d rounded towards -infinity
*/
private static int floordiv(int n, int d) {
return n/d - ( ( n % d != 0 ) && ( (n<0) ^ (d<0) ) ? 1 : 0 );
}

private boolean chunkContainsASpawnPosition(int x, int spacing) {
final int chunksize = 16;
int lowerEdge = floordiv(x-1, spacing);     // without the -1 we'd miss cases where x is a multiple of spacing
int upperEdge = floordiv(x+chunksize -1, spacing);
return upperEdge - lowerEdge == 1;
}

private void generateSurface(World world, Random random, int x, int z)
  if (chunkContainsASpawnPosition(x, 200) && chunkContainsASpawnPosition(z, 100)) {
    // set chunkX etc.
    new Castle.generate(world, random, chunkX, chunkY, chunkZ);
  }
}

 

 

The spawning positions aren't exact multiples of the "spacing" variable but rather the position of the chunk which contains the desired position, i.e. here: z=96, 192, 288, 400, 496, ...

But since you are adding in some random offsets anyway I hope that's ok.

 

Link to comment
Share on other sites

Wow! Thanks a lot! This helps a ton!

 

EDIT: New problem...I have this coding for my mob spawners

TileEntityMobSpawner ttsnimspawner = (TileEntityMobSpawner)world.getTileEntity(i + 6, j + 11, k + 6);
	ttsnimspawner.func_145881_a().setEntityName("Skeleton");

 

When a second structure spawns in, it seems to error on this code. It works fine when there's one structure, but I flew to a second structure and it errored and crashed. I don't understand why... Also, how would I go about adding loot to the chests I have in my dungeon?

Link to comment
Share on other sites

I don't know about the spawners; your code (preceded by "world.setBlock(..., Blocks.mob_spawner)) worked for me.

Maybe you could check whether getTileEntity() returns null, and if so use world.getBlock to see what's in that location.

 

 

For chests:

        world.setBlock(i, j, k, Blocks.chest);
        TileEntityChest chest = (TileEntityChest) world.getTileEntity(i, j, k);
        if (chest == null) {
                System.err.printf("TileEntityChest is null!?!\n");
        } else {
                for (int idx = 0; idx < 4; idx++) {
                        ItemStack stack = new ItemStack(Items.diamond_axe);
                        stack.addEnchantment(Enchantment.efficiency, idx+1);
                        stack.addEnchantment(Enchantment.unbreaking, 10);
                        chest.setInventorySlotContents(idx, stack);
                }
        }

 

 

Link to comment
Share on other sites

Yeap...turns out a jungle biome spawned inside of my structure...so a leaf block replaced the spawner...is there any way to prevent that from happening? I mean, it works now and stuff, but I'd like my dungeons to not be destroyed by the biomes around them.

Link to comment
Share on other sites

The only way of doing this is subscribing to the PopulateChunkEvent.Post event and do your dungeon generation there.

Here's an example:

https://github.com/SanAndreasP/EnderStuffPlus/blob/master/java/de/sanandrew/mods/enderstuffplus/world/EnderStuffWorldGenerator.java#L27-L38

 

Also please note that if you think it is registered with the TERRAIN_GEN_BUS, it isn't, it is with the EVENT_BUS!

Don't ask for support per PM! They'll get ignored! | If a post helped you, click the "Thank You" button at the top right corner of said post! |

mah twitter

This thread makes me sad because people just post copy-paste-ready code when it's obvious that the OP has little to no programming experience. This is not how learning works.

Link to comment
Share on other sites

I'm a little confused...so I would need to run my world generation using EVENT_BUS instead if I added that into it? I can see your generation there is doing both the PopulateChunkEvent and the world generation, so that's why it confused me. Cause right now my world generator is just:

GameRegistry.registerWorldGenerator(new CraftyGirlsWorldGeneration(), 1);

Would that mean I have to make it this instead?

MinecraftForge.EVENT_BUS.register(new CraftyGirlsWorldGeneration());

Link to comment
Share on other sites

You can use a higher number in your registerWorldGenerator so your structures generate after trees and such. I think that might help, but only if you destroy foliage and trees that are in your way.

Link to comment
Share on other sites

I'm a little confused...so I would need to run my world generation using EVENT_BUS instead if I added that into it? I can see your generation there is doing both the PopulateChunkEvent and the world generation, so that's why it confused me. Cause right now my world generator is just:

GameRegistry.registerWorldGenerator(new CraftyGirlsWorldGeneration(), 1);

Would that mean I have to make it this instead?

MinecraftForge.EVENT_BUS.register(new CraftyGirlsWorldGeneration());

 

Keep the EVENT_BUS if you are doing a worldgen.

Developer of MechanicalCraft.

 

Sadly not available to public yet :(

Link to comment
Share on other sites

I'm a little confused...so I would need to run my world generation using EVENT_BUS instead if I added that into it? I can see your generation there is doing both the PopulateChunkEvent and the world generation, so that's why it confused me. Cause right now my world generator is just:

GameRegistry.registerWorldGenerator(new CraftyGirlsWorldGeneration(), 1);

Would that mean I have to make it this instead?

MinecraftForge.EVENT_BUS.register(new CraftyGirlsWorldGeneration());

 

You actually do both, if you use the IWorldGenerator and the PopulateChunkEvent.

 

You could also try sequituri's suggestion. Seems easier (if it works) than fiddling with events.

Don't ask for support per PM! They'll get ignored! | If a post helped you, click the "Thank You" button at the top right corner of said post! |

mah twitter

This thread makes me sad because people just post copy-paste-ready code when it's obvious that the OP has little to no programming experience. This is not how learning works.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.