Jump to content

Recommended Posts

Posted

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;
    }
}

 

Posted

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.

Posted
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

Posted
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?

Posted

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);
        }

 

Posted

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.

Posted
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.

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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Update: I stand corrected as I was able to dig up a relevant log from my earlier testing which highlights the overall issue but does not explain how to solve it. See, Diagnostic Logs for pack.mcmeta not found: https://pastebin.com/LXS8Rtna
    • Which mod was this? What are all the mods that were in use? It will help if enough information to replicate the problem is available.
    • I have been attempting to create a supplementary resource pack with Patchouli in order to add back the guidebook for Better End but unfortunately in every prototype I have made pack.mcmeta and my resource pack are not recognized. I have tested both zipped and unzipped and either way curseforge does not recognize my resource pack as existing. For testing I stripped my pack down to just the pack.mcmeta file and two empty folders labelled data and assets and I know the data folder is not the problem as firstly my first attempts just had an assets folder following Patchouli instructions and data came later in my flailing attempts to make anything in my pack work. The mcmeta file is not recognized whether or not I use this:  { "pack": { "pack_format": 15, "description": "A replacement for the BetterEnd Guide Book." } "language": { "en_US": { "name": "English", "region": "United States" } } } ,or this:  { "pack": { "pack_format": 15, "description": "A replacement for the BetterEnd Guide Book." } } I have made sure to only use lowercase and the pack folder is named better-end-guide. Is this some magic nonsense from me doing this manually instead of using an IDE or similar tool? Could it be because my files are by default in UTF-8 even though ANSI gives the same results? Is there a specific community secret tool I am supposed to use for zipping or specific settings? I am pulling my hair in distress. Unfortunately as there are no errors involved I lack logs to offer, if that disqualifies this thread please do not be harsh and instead if you can then please direct me to a forum with different rules and sufficiently respectful but knowledgeable as to be of assistance. Most of my experience with the programming community has been poor and so naturally I find myself wary.
    • I never picked up a tier 0 dragon skull to my knowledge. One of my other skulls must have bugged out and randomly became one. I was confused on what the heck it was and tried placing it, now the game will only crash because it can't render in whatever the heck the tier 0 skull is. This is on a server and it crashes anyone within render distance.
    • After setting up forge, making sure my drivers are updated, and downloading the create mod i tried to run forge and it said it crashed while trying to render the overlay, i heard about deleting a file called forge-client.toml, but when i looked at the config files(and all the files on my computer) it was nowhere to be found. https://pastebin.com/raw/TTyWWyeS
  • Topics

×
×
  • Create New...

Important Information

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