The problem lies in these lines (48-49) in "WorldGeneratorxlfoodmod":
int randX = blockX + rand.nextInt(16);
int randZ = blockZ + rand.nextInt(16);
You need to add 8 to each coordinate so they are centered within the 2x2 chunk populated area as otherwise you can cause adjacent chunks to load and/or generate, in the worst-case causing an infinite loop which crashes the game (as mentioned in the Reddit link this is probably the single biggest reason why mods that add world generation lag and/or use huge amounts of resources and memory and/or unexpectedly crash when exploring).
Also, in your "getGroundFromAbove" method in "WorldGenxlfoodmod" you can use "World.getHeightValue()" (at least that is what it is called in 1.6.4; vanilla features like trees call it to find the ground level) instead of starting at 255 and check the block below to save time (it will only need to loop more than once if a tree or something is above the ground).
I do have a question regarding this topic and larger structures. If I were to generate large, randomized structures (think an underground, procedurally generated dungeon), how would you go about fixing that because it isn't as simple as adding an offset?
I do have a question regarding this topic and larger structures. If I were to generate large, randomized structures (think an underground, procedurally generated dungeon), how would you go about fixing that because it isn't as simple as adding an offset?
Vanilla gets around this by creating a "map" of the structure in memory and only generating the part that intersects the current area being populated; or, in the case of caves, only carving out blocks within the current chunk (caves do not use an offset and operate on the raw terrain data before it is used to initialize a chunk). To determine if a structure is to be generated before the chunk it is centered in is loaded the game scans a range of chunks around each chunk being generated or populated, setting the seed according to its coordinates (note - use your own Random instance, not the one used to populate chunks or you can cause bugs like MC-2788) and calling the structure's canSpawn() method; the range is set to be larger than the maximum span of the structure (vanilla uses 8, allowing structures to extend up to 8 chunks from the center, with the largest structures being up to 112 blocks or 7 chunks).
Note that this has some limitations, such as not being able to know what the terrain is like before the entire structure is placed (in the case of villages the game calculates the ground level as it places each building; the saving of structures avoids bugs like houses with each half generated at a different level when you reload a world when only part of a village was generated, as could happen in versions prior to 1.6.4), and in the case of caves, they can't see what is in adjacent chunks (this is why they often have a sharp cutoff at a chunk border when next to water and/or water that doesn't flow into them. Normal chunk population avoids this since you can check blocks beyond the 16x16 center area).
Also, structures that are more than 16x16 but less than 32x32 in size can be populated like normal features but with a reduced or no random offset; for example, I reduced the offset for some of the larger trees in my mod so they stay within the allowed area, as well as to prevent them from being too close together (you probably don't want to have no offset at all for trees but for the occasional temple-like structure it doesn't matter).
The problem lies in these lines (48-49) in "WorldGeneratorxlfoodmod":
int randX = blockX + rand.nextInt(16);
int randZ = blockZ + rand.nextInt(16);
You need to add 8 to each coordinate so they are centered within the 2x2 chunk populated area as otherwise you can cause adjacent chunks to load and/or generate, in the worst-case causing an infinite loop which crashes the game (as mentioned in the Reddit link this is probably the single biggest reason why mods that add world generation lag and/or use huge amounts of resources and memory and/or unexpectedly crash when exploring).
I've tried this after I read the Reddit post but I still get the same error.
int randX = blockX + rand.nextInt(16 + 8);
int randZ = blockZ + rand.nextInt(16 + 8);
So in the case of a Stronghold, the game looks like it generates the positions for the Stronghold first and stores them somewhere. At first, I thought it stored them in a map in MapGenStructure but that actually looks like it stores ALL structures ever generated. It looks like the actual pieces that are built are in a list in the StructureStart. I can't see where this gets built out though. Though I think fundamentally, vanilla Strongholds are using generatePositions to generate the structure without placing any of the blocks. Then StructureStart is called and it generates the actual pieces and builds them. One thing I don't understand though is where and how does vanilla generate and build a portion of a structure, and not the parts that are in unloaded chunks (or non-generated chunks).
One thing I don't understand though is where and how does vanilla generate and build a portion of a structure, and not the parts that are in unloaded chunks (or non-generated chunks).
This is done in the method that is called when a chunk is populated, which is (in 1.6.4) "generateStructuresInChunk", which checks to see if the bounding boxes of each structure stored within the structure map intersects the current chunk (or rather, offset chunk area), with a further check done for each individual structure piece in StructureStart (which has its own list of individual components), and yet another on each get/setblock call, which are placed inside of wrapper methods in StructureComponent which compare the coordinates of each block to the bounding box of the area being populated.
Also, the fact that the game iterates over the entire structure map in MapGenStructure explains MC-33134, as it has to iterate through more and more structures as time goes on (not just when generating them, but when determining if structure-specific mobs should spawn and anything else that needs to check for a structure), which is particularly significant for mineshafts because they are so common and rather complex; structure saving amplifies this since all structures ever created, not just in chunks loaded in the current session, are stored.
{
int randX = blockX + rand.nextInt(16 + 8);
int randZ = blockZ + rand.nextInt(16 + 8);
genVanillaFlower.generate(world, rand, new BlockPos(randX + 8, 24, randZ + 8));
}
No, like this:
int randX = blockX + rand.nextInt(16) + 8;
int randZ = blockZ + rand.nextInt(16) + 8;
The 8 is only added directly to the coordinates, not to the random offset that is added (you can see how vanilla does this in the BiomeDecorator class; note that WorldGenMinable adds 8 internally so it is one of the exceptions to the "add 8" rule).
This is done in the method that is called when a chunk is populated, which is (in 1.6.4) "generateStructuresInChunk", which checks to see if the bounding boxes of each structure stored within the structure map intersects the current chunk (or rather, offset chunk area), with a further check done for each individual structure piece in StructureStart (which has its own list of individual components), and yet another on each get/setblock call, which are placed inside of wrapper methods in StructureComponent which compare the coordinates of each block to the bounding box of the area being populated.
Also, the fact that the game iterates over the entire structure map in MapGenStructure explains MC-33134, as it has to iterate through more and more structures as time goes on (not just when generating them, but when determining if structure-specific mobs should spawn and anything else that needs to check for a structure), which is particularly significant for mineshafts because they are so common and rather complex; structure saving amplifies this since all structures ever created, not just in chunks loaded in the current session, are stored.
Ok, that makes sense. If I'm understanding this correctly, what I need to do is generate the structure through a WorldGenerator like normal (with an offset), but first just generate the positions of each individual structure (through the algorithm I've created). In order to prevent runaway chunk generation, I need to check to make sure each individual structure (which has a StructureBoundingBox) is intersecting with the current chunk (which is offset). If yes, generate the actual structure, else don't. In terms of generating the pieces that don't pass the initial check, would I just have a loop or something in the WorldGenerator which loops through all the pending structures checking to see if they intersect with a newly loaded chunk? (I'm assuming WorldGenerator#generate is called once per chunk IIRC).
I just want to make sure I'm not misunderstanding anything before I implement it.
I've recently noticed that when I load a new world I get cascading world gen error. How to fix this?
Thanks!
World Generator Class : https://pastebin.com/MzaGqdXC
World Gen Class: https://pastebin.com/xEVuyLg4
Read this Reddit post - it goes into very good detail about explaining the issue and fixing it as well.
The problem lies in these lines (48-49) in "WorldGeneratorxlfoodmod":
You need to add 8 to each coordinate so they are centered within the 2x2 chunk populated area as otherwise you can cause adjacent chunks to load and/or generate, in the worst-case causing an infinite loop which crashes the game (as mentioned in the Reddit link this is probably the single biggest reason why mods that add world generation lag and/or use huge amounts of resources and memory and/or unexpectedly crash when exploring).
Also, in your "getGroundFromAbove" method in "WorldGenxlfoodmod" you can use "World.getHeightValue()" (at least that is what it is called in 1.6.4; vanilla features like trees call it to find the ground level) instead of starting at 255 and check the block below to save time (it will only need to loop more than once if a tree or something is above the ground).
TheMasterCaver's First World - possibly the most caved-out world in Minecraft history - includes world download.
TheMasterCaver's World - my own version of Minecraft largely based on my views of how the game should have evolved since 1.6.4.
Why do I still play in 1.6.4?
I do have a question regarding this topic and larger structures. If I were to generate large, randomized structures (think an underground, procedurally generated dungeon), how would you go about fixing that because it isn't as simple as adding an offset?
Vanilla gets around this by creating a "map" of the structure in memory and only generating the part that intersects the current area being populated; or, in the case of caves, only carving out blocks within the current chunk (caves do not use an offset and operate on the raw terrain data before it is used to initialize a chunk). To determine if a structure is to be generated before the chunk it is centered in is loaded the game scans a range of chunks around each chunk being generated or populated, setting the seed according to its coordinates (note - use your own Random instance, not the one used to populate chunks or you can cause bugs like MC-2788) and calling the structure's canSpawn() method; the range is set to be larger than the maximum span of the structure (vanilla uses 8, allowing structures to extend up to 8 chunks from the center, with the largest structures being up to 112 blocks or 7 chunks).
Note that this has some limitations, such as not being able to know what the terrain is like before the entire structure is placed (in the case of villages the game calculates the ground level as it places each building; the saving of structures avoids bugs like houses with each half generated at a different level when you reload a world when only part of a village was generated, as could happen in versions prior to 1.6.4), and in the case of caves, they can't see what is in adjacent chunks (this is why they often have a sharp cutoff at a chunk border when next to water and/or water that doesn't flow into them. Normal chunk population avoids this since you can check blocks beyond the 16x16 center area).
Also, structures that are more than 16x16 but less than 32x32 in size can be populated like normal features but with a reduced or no random offset; for example, I reduced the offset for some of the larger trees in my mod so they stay within the allowed area, as well as to prevent them from being too close together (you probably don't want to have no offset at all for trees but for the occasional temple-like structure it doesn't matter).
TheMasterCaver's First World - possibly the most caved-out world in Minecraft history - includes world download.
TheMasterCaver's World - my own version of Minecraft largely based on my views of how the game should have evolved since 1.6.4.
Why do I still play in 1.6.4?
I've tried this after I read the Reddit post but I still get the same error.
You need to add the 8 to your block position first.
So in the case of a Stronghold, the game looks like it generates the positions for the Stronghold first and stores them somewhere. At first, I thought it stored them in a map in MapGenStructure but that actually looks like it stores ALL structures ever generated. It looks like the actual pieces that are built are in a list in the StructureStart. I can't see where this gets built out though. Though I think fundamentally, vanilla Strongholds are using generatePositions to generate the structure without placing any of the blocks. Then StructureStart is called and it generates the actual pieces and builds them. One thing I don't understand though is where and how does vanilla generate and build a portion of a structure, and not the parts that are in unloaded chunks (or non-generated chunks).
This is done in the method that is called when a chunk is populated, which is (in 1.6.4) "generateStructuresInChunk", which checks to see if the bounding boxes of each structure stored within the structure map intersects the current chunk (or rather, offset chunk area), with a further check done for each individual structure piece in StructureStart (which has its own list of individual components), and yet another on each get/setblock call, which are placed inside of wrapper methods in StructureComponent which compare the coordinates of each block to the bounding box of the area being populated.
Also, the fact that the game iterates over the entire structure map in MapGenStructure explains MC-33134, as it has to iterate through more and more structures as time goes on (not just when generating them, but when determining if structure-specific mobs should spawn and anything else that needs to check for a structure), which is particularly significant for mineshafts because they are so common and rather complex; structure saving amplifies this since all structures ever created, not just in chunks loaded in the current session, are stored.
TheMasterCaver's First World - possibly the most caved-out world in Minecraft history - includes world download.
TheMasterCaver's World - my own version of Minecraft largely based on my views of how the game should have evolved since 1.6.4.
Why do I still play in 1.6.4?
Like this?
No, like this:
The 8 is only added directly to the coordinates, not to the random offset that is added (you can see how vanilla does this in the BiomeDecorator class; note that WorldGenMinable adds 8 internally so it is one of the exceptions to the "add 8" rule).
TheMasterCaver's First World - possibly the most caved-out world in Minecraft history - includes world download.
TheMasterCaver's World - my own version of Minecraft largely based on my views of how the game should have evolved since 1.6.4.
Why do I still play in 1.6.4?
Ok, that makes sense. If I'm understanding this correctly, what I need to do is generate the structure through a WorldGenerator like normal (with an offset), but first just generate the positions of each individual structure (through the algorithm I've created). In order to prevent runaway chunk generation, I need to check to make sure each individual structure (which has a StructureBoundingBox) is intersecting with the current chunk (which is offset). If yes, generate the actual structure, else don't. In terms of generating the pieces that don't pass the initial check, would I just have a loop or something in the WorldGenerator which loops through all the pending structures checking to see if they intersect with a newly loaded chunk? (I'm assuming WorldGenerator#generate is called once per chunk IIRC).
I just want to make sure I'm not misunderstanding anything before I implement it.
Alright, I finally solved the issue. Thanks to both of you guys!
Btw, when I register WorldGenerator should it be in preInit or Init because both work, is there a difference?
It probably doesn't matter too much. I personally have mine registered in init.