Jump to content

[1.16.5] How to set biome at specific chunk?


sasetz

Recommended Posts

I want to create a block that changes chunk biome after player clicks on it. I've found some old tutorials (for Minecraft 1.10) on how to do this but when I tried to do the same, needed methods just aren't there anymore. Is it even possible on newer versions?
Thanks!

Link to comment
Share on other sites

Thank you for your reply!
 

16 minutes ago, diesieben07 said:

However this might be null if the chunk is not fully generated yet - in that case Minecraft will fall back to simply using the world generation algorithm to find the biomes. If however it exists, you can use reflection to hack its internal biomes array. See BiomeContainer#getNoiseBiome to see how this array is used.

The block will be placed by a player, so, the chunk is generated. So, I need to create an access transformer to change biome array's signature from "private final" to "public", right?

18 minutes ago, diesieben07 said:

This however is the unzoomed biome. World#getBiomeManager applies an additional zoom on top of this.


What does it mean "unzoomed biome"? And how do I apply zoom with BiomeManager?

Edited by sasetz
Added quotes
Link to comment
Share on other sites

Thank you for your replies!

8 hours ago, diesieben07 said:

Keep it final. But yes, you can AT it. But you could also use reflection.

I created an AT and checked what's inside of this array. Why is there 1024 Biome instances? Is it 4 instances for each block in a chunk or what? I inspected BiomeContainer#getNoiseBiome, but it didn't make much sense since I don't know what 3 int parameters supposed to mean (xyz? I thought biome stretches from y=0 to y=255. Maybe it's 16x16 and 4 layers vertically? idk)
I've tried changing stuff inside of the array (using BiomeMaker methods) but after I did that, when I checked again the array and the registry names of biomes inside are all null. After I restart the world it turns back to normal (minecraft:plains or more)

9 hours ago, diesieben07 said:

See BiomeManager#getBiome(BlockPos).

So I need to call this method on every block inside of chunk, so it gets zoomed? I don't think it's what you meant though...

Link to comment
Share on other sites

Thanks for you reply!

1 hour ago, diesieben07 said:

So if you want to change the biome at a certain x, y, z coord, you have to use the zoomer as well (but in reverse) before accessing the biomes array.

Ok, I've figured it out that chunk is divided to cubes with 4 blocks side and each of the cubes has it's own biome. But still, I want to change biome in the whole chunk, so I change every element of the array to another biome and it doesn't change (registry name says it's null biome), and the changes don't save (when I reload the world, biomes are back to normal)

Link to comment
Share on other sites

12 minutes ago, diesieben07 said:

Show your code.

if(!level.isClientSide()){
    Biome[] biomes = level.getChunkAt(worldPosition).getBiomes().biomes;
    sendToChat(BiomeMaker.desertBiome(.125f, .05f, false, false, false).toString());
    for (int i = 0, biomesLength = biomes.length; i < biomesLength; i++) {
        biomes[i] = BiomeMaker.desertBiome(.125f, .05f, false, false, false);
        sendToChat("" + i + ": " + biomes[i].getRegistryName());
    }
}

This is a piece of code is called when I right click on a block, it's inside of a TileEntity

Link to comment
Share on other sites

7 minutes ago, diesieben07 said:

World#registryAccess gives you the DynamicRegistries. From there you can get the biome registry and then look up the biomes.

And then what field or method should I call? I just couldn't find anything suitable

Link to comment
Share on other sites

32 minutes ago, diesieben07 said:

DynamicRegistries#registry with the RegistryKey for biomes (Registry.BIOME_REGISTRY). Then you have the biome registry. Then Registry#get.

Now it's doing a NullPointerException... 
I just did this

level.registryAccess().registry(Registry.BIOME_REGISTRY).get().get(Biomes.DESERT.getRegistryName()).toString()

The second get method returns null

Link to comment
Share on other sites

Instead of getting the desert biome I just typed new ResourceLocation("minecraft:desert") and it finally worked!

The final code is

public void changeBiome() {
    Biome[] biomes = level.getChunkAt(worldPosition).getBiomes().biomes;
    for (int i = 0, biomesLength = biomes.length; i < biomesLength; i++) {
        DynamicRegistries reg = level.registryAccess();
        MutableRegistry<Biome> a = reg.registry(Registry.BIOME_REGISTRY).get();
        Biome biome = a.get(new ResourceLocation("minecraft:desert"));
        biomes[i] = biome;
    }
}

 

But the only thing left is that the grass color doesn't change instantly, but when I click F3 + A (only if I click the combination twice) it looks how it should be (grass changes from plains green to yellow)
If I hit F3 + A only 1 time, the borders between biomes become sharp between the chunks
https://imgur.com/a/9qNBhxS (screenshot)

Is there a way to reload a chunk like F3 + A does?
And thank you for all of your replies!

Edited by sasetz
updated code
Link to comment
Share on other sites

23 minutes ago, diesieben07 said:

Biomes.DESERT is a registry key. Calling getRegistryName gives you the name of the registry. RegistryKey#location gives you the name of the biome.

Biomes.DESERT.location() returns the correct ResourceLocation (minecraft:desert)

1 hour ago, diesieben07 said:

1) the client doesn't know that the biome has changed

No, the client knows about the biome change, since this method fires on both sides. If it works only on server side, the client needs to revisit a chunk, F3 + A is not enough

2 hours ago, diesieben07 said:

2) that the client doesn't re-render the chunk

Yes, that's basically what I need. Is SChunkDataPacket going to fix this issue? If so, how can I send this vanilla packet?

Link to comment
Share on other sites

15 minutes ago, diesieben07 said:

You should really only do this server side if you can help it and then update the clients using the packet.

Ok, that makes sense

15 minutes ago, diesieben07 said:

Yes, but it's the brute-force approach because it re-sends the entire chunk data.

I understand that and still, how do I send this packet? I found info only about custom packets, not the vanilla ones

Link to comment
Share on other sites

Thank you for your replies!

3 hours ago, diesieben07 said:

Look at what PacketDistributor#trackingChunk does.

I've done the same thing that this method does, but the problem on screenshot (https://imgur.com/a/9qNBhxS) remains. Sometimes everything changes ok but the rest of the times the result is the same as in the screenshot. Breaking/placing block inside the chunk fixes the problem

    public void changeBiome() {
        if(!level.isClientSide()){
            // Now this piece of code runs only on server side
            final Chunk chunk = level.getChunkAt(worldPosition);
            Biome[] biomes = chunk.getBiomes().biomes;
            for (int i = 0, biomesLength = biomes.length; i < biomesLength; i++) {
                DynamicRegistries reg = level.registryAccess();
                MutableRegistry<Biome> a = reg.registry(Registry.BIOME_REGISTRY).get();
                Biome biome = a.get(Biomes.DESERT.location());
                biomes[i] = biome;
            }
            // This line does basically the same that PacketDistributor#trackingChunk does
            ((ServerChunkProvider)level.getChunkSource()).chunkMap.getPlayers(chunk.getPos(), false)
                    .forEach(e -> e.connection.send(new SChunkDataPacket(chunk, 65535)));
        }
        else {
            // Update chunk?
        }
    }

I guess that the only thing remains is to update the chunk on client, how can I do that?

Link to comment
Share on other sites

26 minutes ago, diesieben07 said:

I am sorry, but I don't know why it doesn't work. The client receives the chunk data packet and ithas the correct biomes in it. It then decides to re-render the chunk. I don't know why it renders with the wrong colors.

Well, still, thank you for your help! I will continue searching for what's happening, so if I find something, I'll post it here

So far I figured out that the update doesn't affect the whole chunk, several layers of grass or leaves can be different colors at the same time

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.

×
×
  • Create New...

Important Information

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