Posted May 8, 20241 yr So i have a custom ore and, arround the ore, a bunch of randomly placed custom stone blocks should be placed. After applying it, i've found that it causes moderate to extreme world generation lag (new chunks refusing to load after moving for a while, height slices of the same chunk appearing and disappearing as I get into them instead of the usual long continous chunk, new chunks generating extremely close to me instead of to the set render distance...) I've been debugging for a while and I know for a fact this is causing the lag (and sometimes freeze of the world loading screen on a new world and/or the saving world screen when quitting), since comenting it just makes the worldgen work as usual and I want to see if its really that computationally expensive, if there are other ways of doing it or if the process can be simplfied or optimized. I've tried a lot of combinations for the same code but I am just stuck. Is it some kind of generation cascading im missing? Here is the code for the class. The code inside the if (placed) is the one causing this mess. I can see that the code might not be the most optimized thing, but it does what's supposed to... but at the cost of causing all this. Any tips? package es.nullbyte.relativedimensions.worldgen.oregen.oreplacements; import es.nullbyte.relativedimensions.blocks.BlockInit; import es.nullbyte.relativedimensions.blocks.ModBlockTags; import net.minecraft.core.BlockPos; import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; import net.minecraft.world.level.levelgen.feature.OreFeature; import net.minecraft.world.level.levelgen.feature.configurations.OreConfiguration; import java.util.Optional; public class AberrantOreFeature extends OreFeature { public AberrantOreFeature() { super(OreConfiguration.CODEC); } @Override public boolean place(FeaturePlaceContext<OreConfiguration> ctx) { // Get the world and the position from the context WorldGenLevel world = ctx.level(); BlockPos origin = ctx.origin(); // Offset the origin by 8 in the x and z directions to avoid cascading chunk generation BlockPos offsetOrigin = origin.offset(8, 0, 8); // Create a new context with the offset origin FeaturePlaceContext<OreConfiguration> offsetCtx = new FeaturePlaceContext<>( Optional.empty(), world, ctx.chunkGenerator(), ctx.random(), offsetOrigin, ctx.config() ); // Generate the entire vein of ore at the offset origin boolean placed = super.place(offsetCtx); // If the vein was generated successfully if (placed) { // Define the block to replace surrounding blocks with BlockState surroundingBlockState = BlockInit.ABERRANT_MINERALOID.get().defaultBlockState(); // Generate a random size for the area of corruption int areaSizeX = ctx.random().nextInt(3) + 1; // between 1 and 4 int areaSizeY = ctx.random().nextInt(3) + 1; // between 1 and 4 int areaSizeZ = ctx.random().nextInt(3) + 1; // between 1 and 4 // Calculate the number of blocks to be corrupted based on the area size double numBlocksToCorrupt = (areaSizeX + areaSizeY + areaSizeZ / 2.0) ; // Counter for the number of blocks corrupted int numBlocksCorrupted = 0; // Loop for each block to be corrupted while (numBlocksCorrupted < numBlocksToCorrupt) { // Generate a random position within the area, using the offset origin BlockPos randomPos = offsetOrigin.offset( ctx.random().nextInt(2 * areaSizeX + 1) - areaSizeX, // between -areaSize and areaSize ctx.random().nextInt(2 * areaSizeY + 1) - areaSizeY, ctx.random().nextInt(2 * areaSizeZ + 1) - areaSizeZ ); // If the block at the random position is in the IS_ORE_ABERRANTABLE tag, replace it if (world.getBlockState(randomPos).is(ModBlockTags.STONE_ABERRANTABLE)) { world.setBlock(randomPos, surroundingBlockState, 2); numBlocksCorrupted++; } } } return placed; } }
May 8, 20241 yr Your mod is probably lagging during world generation due to how it replaces blocks around your custom ore. Right now, it randomly picks spots around the ore and changes blocks there. This process can be slow, especially if it's dealing with lots of blocks or a big area. To fix it, try replacing fewer blocks, picking spots more efficiently, and changing blocks in a smarter way. This should help your mod run smoother when generating worlds. Here is an example of how you can do this // Inside the if (placed) block if (placed) { BlockState surroundingBlockState = BlockInit.ABERRANT_MINERALOID.get().defaultBlockState(); int veinSize = ctx.config().size; int maxBlocksToReplace = (int) Math.ceil(veinSize * 0.1); // Replace 10% of vein size int numBlocksToCorrupt = Math.min(maxBlocksToReplace, 1000); // Limit to 1000 blocks List<BlockPos> positionsToReplace = new ArrayList<>(); // Loop until reaching the limit of blocks to replace while (positionsToReplace.size() < numBlocksToCorrupt) { BlockPos randomPos = offsetOrigin.offset( ctx.random().nextInt(2 * areaSizeX + 1) - areaSizeX, ctx.random().nextInt(2 * areaSizeY + 1) - areaSizeY, ctx.random().nextInt(2 * areaSizeZ + 1) - areaSizeZ ); if (world.getBlockState(randomPos).is(ModBlockTags.STONE_ABERRANTABLE)) { positionsToReplace.add(randomPos); } } // Replace blocks in bulk for (BlockPos pos : positionsToReplace) { world.setBlock(pos, surroundingBlockState, 2); } } If you've tried more effective ways to generate your blocks around your ores, it may also be because of issues on your side, not the mod. Adjust the parameters as needed based on your performance testing and requirements.
May 8, 20241 yr Author 9 minutes ago, AwesomeDev said: Your mod is probably lagging during world generation due to how it replaces blocks around your custom ore. Right now, it randomly picks spots around the ore and changes blocks there. This process can be slow, especially if it's dealing with lots of blocks or a big area. To fix it, try replacing fewer blocks, picking spots more efficiently, and changing blocks in a smarter way. This should help your mod run smoother when generating worlds. Here is an example of how you can do this // Inside the if (placed) block if (placed) { BlockState surroundingBlockState = BlockInit.ABERRANT_MINERALOID.get().defaultBlockState(); int veinSize = ctx.config().size; int maxBlocksToReplace = (int) Math.ceil(veinSize * 0.1); // Replace 10% of vein size int numBlocksToCorrupt = Math.min(maxBlocksToReplace, 1000); // Limit to 1000 blocks List<BlockPos> positionsToReplace = new ArrayList<>(); // Loop until reaching the limit of blocks to replace while (positionsToReplace.size() < numBlocksToCorrupt) { BlockPos randomPos = offsetOrigin.offset( ctx.random().nextInt(2 * areaSizeX + 1) - areaSizeX, ctx.random().nextInt(2 * areaSizeY + 1) - areaSizeY, ctx.random().nextInt(2 * areaSizeZ + 1) - areaSizeZ ); if (world.getBlockState(randomPos).is(ModBlockTags.STONE_ABERRANTABLE)) { positionsToReplace.add(randomPos); } } // Replace blocks in bulk for (BlockPos pos : positionsToReplace) { world.setBlock(pos, surroundingBlockState, 2); } } If you've tried more effective ways to generate your blocks around your ores, it may also be because of issues on your side, not the mod. Adjust the parameters as needed based on your performance testing and requirements. I've tested the same code on three different envionrments (Desktop win10, desktop Linux and Laptop Linux) and it kinda blows up all the same. Gonna try this code and see if i can tune it
May 9, 20241 yr Author 38 minutes ago, AwesomeDev said: Your mod is probably lagging during world generation due to how it replaces blocks around your custom ore. Right now, it randomly picks spots around the ore and changes blocks there. This process can be slow, especially if it's dealing with lots of blocks or a big area. To fix it, try replacing fewer blocks, picking spots more efficiently, and changing blocks in a smarter way. This should help your mod run smoother when generating worlds. Here is an example of how you can do this // Inside the if (placed) block if (placed) { BlockState surroundingBlockState = BlockInit.ABERRANT_MINERALOID.get().defaultBlockState(); int veinSize = ctx.config().size; int maxBlocksToReplace = (int) Math.ceil(veinSize * 0.1); // Replace 10% of vein size int numBlocksToCorrupt = Math.min(maxBlocksToReplace, 1000); // Limit to 1000 blocks List<BlockPos> positionsToReplace = new ArrayList<>(); // Loop until reaching the limit of blocks to replace while (positionsToReplace.size() < numBlocksToCorrupt) { BlockPos randomPos = offsetOrigin.offset( ctx.random().nextInt(2 * areaSizeX + 1) - areaSizeX, ctx.random().nextInt(2 * areaSizeY + 1) - areaSizeY, ctx.random().nextInt(2 * areaSizeZ + 1) - areaSizeZ ); if (world.getBlockState(randomPos).is(ModBlockTags.STONE_ABERRANTABLE)) { positionsToReplace.add(randomPos); } } // Replace blocks in bulk for (BlockPos pos : positionsToReplace) { world.setBlock(pos, surroundingBlockState, 2); } } If you've tried more effective ways to generate your blocks around your ores, it may also be because of issues on your side, not the mod. Adjust the parameters as needed based on your performance testing and requirements. Ok so this specific code freezes the game on world creation. This is what gets me so confused, i get that it might not be the best thing, but is it really so generation heavy?
May 9, 20241 yr Author I think i've found a more "generation friendly way" of generating random blobs of mineral around the ore. This both does the trick and make the generation work flawlessly (albeit i need to make some adjustments). I just ended up thinking "MAYBE there is another Feature I can use to place the minerals instead of doing it manually" And, low and behold, SCATTERED_ORE is actually a thing. I don't really know how "orthodox" this solution is, but it works and rids me of all the problems I had witht my original "manual" implementation. If anybody has any insight on why my original class could've been causing lag to the point of freezes and chunk generation just refusing to keep loading new chunks, I'm also all ears: Here is the full if (placed) block for anyone with a smiliar issue: if (placed) { // Define the block to replace surrounding blocks with BlockState surroundingBlockState = BlockInit.ABERRANT_MINERALOID.get().defaultBlockState(); RuleTest stoneReplacement = new TagMatchTest(BlockTags.STONE_ORE_REPLACEABLES); //Tag which indicates ores that can replace stone RuleTest deepslateReplacement = new TagMatchTest(BlockTags.DEEPSLATE_ORE_REPLACEABLES); //Tag which indicates ores that can replace deepslate // Create a list of TargetBlockState for the Aberrant Mineraloids List<OreConfiguration.TargetBlockState> targets = new ArrayList<>(); targets.add(OreConfiguration.target(stoneReplacement, surroundingBlockState)); targets.add(OreConfiguration.target(deepslateReplacement, surroundingBlockState)); // Create a new OreConfiguration for the Aberrant Mineraloids OreConfiguration mineraloidConfig = new OreConfiguration(targets, 9); // vein size // Create a new context for the Aberrant Mineraloids FeaturePlaceContext<OreConfiguration> mineraloidCtx = new FeaturePlaceContext<>( Optional.empty(), world, ctx.chunkGenerator(), ctx.random(), offsetOrigin, mineraloidConfig ); // Generate the Aberrant Mineraloids using the SCATTERED_ORE configuration boolean mineraloidsPlaced = Feature.SCATTERED_ORE.place(mineraloidCtx); }
May 9, 20241 yr I might have an idea why your original method was causing so much trouble. See this while loop? 17 hours ago, chxr said: while (numBlocksCorrupted < numBlocksToCorrupt) { // Generate a random position within the area, using the offset origin BlockPos randomPos = offsetOrigin.offset( ctx.random().nextInt(2 * areaSizeX + 1) - areaSizeX, // between -areaSize and areaSize ctx.random().nextInt(2 * areaSizeY + 1) - areaSizeY, ctx.random().nextInt(2 * areaSizeZ + 1) - areaSizeZ ); // If the block at the random position is in the IS_ORE_ABERRANTABLE tag, replace it if (world.getBlockState(randomPos).is(ModBlockTags.STONE_ABERRANTABLE)) { world.setBlock(randomPos, surroundingBlockState, 2); numBlocksCorrupted++; } } You're only incrementing the number of blocks you've corrupted if you find one that you can corrupt. What happens if you can't find any? The while loop will run forever (a long time). This could happen if, for instance, the feature generates inside a vein of blocks that aren't marked as STONE_ABERRANTABLE. There are two alternate strategies I'd recommend to fix this. First, you could simply increment numBlockCorrupted regardless of whether you've actually corrupted the block. This is the simplest and quickest way, and it should ensure that the loop runs no more than numBlocksToCorrupt times. Alternatively, you could add a "kill switch" that keeps track of how many times the loop runs, and then ends it after a certain limit of your choosing. That could look something like this: // Keeps track of how many blocks have been checked so far. int numBlocksChecked = 0; // Check up to twice as many blocks as you actually want to corrupt. // This is a good compromise between speed and actually getting the number of blocks // that you want to corrupt. int numBlocksToCheck = numBlocksToCorrupt * 2; // Modified the while loop condition to end after a certain number of blocks are checked. while (numBlocksCorrupted < numBlocksToCorrupt && numBlocksChecked < numBlocksToCheck) { // Generate a random position within the area, using the offset origin BlockPos randomPos = offsetOrigin.offset( ctx.random().nextInt(2 * areaSizeX + 1) - areaSizeX, // between -areaSize and areaSize ctx.random().nextInt(2 * areaSizeY + 1) - areaSizeY, ctx.random().nextInt(2 * areaSizeZ + 1) - areaSizeZ ); // If the block at the random position is in the IS_ORE_ABERRANTABLE tag, replace it if (world.getBlockState(randomPos).is(ModBlockTags.STONE_ABERRANTABLE)) { world.setBlock(randomPos, surroundingBlockState, 2); numBlocksCorrupted++; } // Increment the number of blocks that you've checked. numBlocksChecked++; } Let me know if you're still running into lag problems or are confused by my explanation.
May 9, 20241 yr Author 4 hours ago, scientistknight1 said: I might have an idea why your original method was causing so much trouble. See this while loop? You're only incrementing the number of blocks you've corrupted if you find one that you can corrupt. What happens if you can't find any? The while loop will run forever (a long time). This could happen if, for instance, the feature generates inside a vein of blocks that aren't marked as STONE_ABERRANTABLE. There are two alternate strategies I'd recommend to fix this. First, you could simply increment numBlockCorrupted regardless of whether you've actually corrupted the block. This is the simplest and quickest way, and it should ensure that the loop runs no more than numBlocksToCorrupt times. Alternatively, you could add a "kill switch" that keeps track of how many times the loop runs, and then ends it after a certain limit of your choosing. That could look something like this: // Keeps track of how many blocks have been checked so far. int numBlocksChecked = 0; // Check up to twice as many blocks as you actually want to corrupt. // This is a good compromise between speed and actually getting the number of blocks // that you want to corrupt. int numBlocksToCheck = numBlocksToCorrupt * 2; // Modified the while loop condition to end after a certain number of blocks are checked. while (numBlocksCorrupted < numBlocksToCorrupt && numBlocksChecked < numBlocksToCheck) { // Generate a random position within the area, using the offset origin BlockPos randomPos = offsetOrigin.offset( ctx.random().nextInt(2 * areaSizeX + 1) - areaSizeX, // between -areaSize and areaSize ctx.random().nextInt(2 * areaSizeY + 1) - areaSizeY, ctx.random().nextInt(2 * areaSizeZ + 1) - areaSizeZ ); // If the block at the random position is in the IS_ORE_ABERRANTABLE tag, replace it if (world.getBlockState(randomPos).is(ModBlockTags.STONE_ABERRANTABLE)) { world.setBlock(randomPos, surroundingBlockState, 2); numBlocksCorrupted++; } // Increment the number of blocks that you've checked. numBlocksChecked++; } Let me know if you're still running into lag problems or are confused by my explanation. Yeah I had a similar idea, at some point I also just got the numBlocksCorrupted++ out of the if block so it would just do a loop numBlocksCorrupted amount of times but it still caused some troubles. I've ended up using an extra feature to generate the blob around the ore and its working wonders so I won't be scratching my head much longer with it
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.