sasetz Posted August 3, 2021 Share Posted August 3, 2021 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! Quote Link to comment Share on other sites More sharing options...
sasetz Posted August 3, 2021 Author Share Posted August 3, 2021 (edited) 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 August 3, 2021 by sasetz Added quotes Quote Link to comment Share on other sites More sharing options...
sasetz Posted August 4, 2021 Author Share Posted August 4, 2021 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... Quote Link to comment Share on other sites More sharing options...
sasetz Posted August 4, 2021 Author Share Posted August 4, 2021 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) Quote Link to comment Share on other sites More sharing options...
sasetz Posted August 4, 2021 Author Share Posted August 4, 2021 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 Quote Link to comment Share on other sites More sharing options...
sasetz Posted August 4, 2021 Author Share Posted August 4, 2021 5 minutes ago, diesieben07 said: What does this method do? It's method that returns Biome, there's a bunch of those for each biome inside BiomeMaker class Quote Link to comment Share on other sites More sharing options...
Luis_ST Posted August 4, 2021 Share Posted August 4, 2021 1 minute ago, diesieben07 said: Please show it... this is the default vanilla method in 1.16.5 minecraft use this method to create the DesertBiome Quote Link to comment Share on other sites More sharing options...
sasetz Posted August 4, 2021 Author Share Posted August 4, 2021 Just now, diesieben07 said: Oh... well that would explain it then. You can't create a new biome. You have to use the desert biome from the world's dynamic registries. I've tried this, but how do I turn RegistryKey to Biome? Quote Link to comment Share on other sites More sharing options...
sasetz Posted August 4, 2021 Author Share Posted August 4, 2021 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 Quote Link to comment Share on other sites More sharing options...
sasetz Posted August 4, 2021 Author Share Posted August 4, 2021 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 Quote Link to comment Share on other sites More sharing options...
sasetz Posted August 4, 2021 Author Share Posted August 4, 2021 14 minutes ago, diesieben07 said: Hm, that is curious. Use the debugger to see what the registry contains. For some reason the code Biomes.DESERT.getRegistryName().toString() returns "minecraft:worldgen/biome"... Quote Link to comment Share on other sites More sharing options...
sasetz Posted August 4, 2021 Author Share Posted August 4, 2021 (edited) 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 August 4, 2021 by sasetz updated code Quote Link to comment Share on other sites More sharing options...
sasetz Posted August 5, 2021 Author Share Posted August 5, 2021 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? Quote Link to comment Share on other sites More sharing options...
sasetz Posted August 5, 2021 Author Share Posted August 5, 2021 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 Quote Link to comment Share on other sites More sharing options...
sasetz Posted August 5, 2021 Author Share Posted August 5, 2021 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? Quote Link to comment Share on other sites More sharing options...
sasetz Posted August 5, 2021 Author Share Posted August 5, 2021 1 hour ago, diesieben07 said: SChunkDataPacket does this when it is received on the client. I am not sure why it doesn't work for you. Please post a Git repo of your mod so I can test this. https://github.com/sasetz/biome_changer_block Quote Link to comment Share on other sites More sharing options...
sasetz Posted August 5, 2021 Author Share Posted August 5, 2021 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 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.