Jump to content

[1.12.2] Make biomes spawn only in specific locations


Recommended Posts

I would like to control where biomes spawn. I'd like them only to spawn at certain Z values depending on their temperature. I think I'm poking around in the right set of classes (BiomeProvider and GenLayerBiome), but this world gen stuff is so convoluted, it's taking me forever to make tiny bits of progress. If someone can point me in the right direction and tell me which methods to look at and what bits to tweak, I'd much appreciate it.

Link to comment
Share on other sites

I have a fair bit of tutorial information on custom dimensions, biomes and such. See: http://jabelarminecraft.blogspot.com/p/minecraft-forge-1721710-biome-quick-tips.html. There is a link to a fully custom dimension tutorial in there as well.


You're right that the vanilla code is extremely convoluted -- it has redundant fields that point at each other, it uses terms that sound similar like generate, decorate, populate, and there are things called "world gen" that are actually just featues, but not full worlds. There are recursive structures, and so on.


But the thing to remember is that after all the generation is simply placing blocks and actually as long as you get blocks where you want them it is all good.


However, in your case you might be able to get by mostly by using the biome "type" both in the BiomeManager and BiomeDictionary. Those both have category tags for your biome like "COOL" to help the vanilla generators properly mix biomes.


Regarding it only generating on certain Z values though that might be a bit trickier. One way might be to have the chunk generator's biome map replace your biome with another similar vanilla one whenever the Z doesn't match. Not sure how easy that would be exactly.


The most control would come from making a custom dimension. You could basically copy the overworld but when it is selecting the biomes during generation you could check the Z and force your biome when desired.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

I've read your tutorial. In fact, your site is often my first stopping point when doing research. That's what got me looking at BiomeProvider and GenLayerBiome. I'm pretty sure this is where the biomes are actually chosen, but most of the variables and numbers are totally cryptic to me at this point.


I already have a custom dimension and chunk generator that mostly mimics ChunkGeneratorOverworld (the only change I've made so far is to remove some vanilla structures). It looks like setBlocksInChunk gets the biomes that are supposed to be generated for a new chunk. I think it gives a list with a biome assigned to each column in the chunk. I could edit the list right there, except it seems like I'd have a hard time making sure I stitch the biomes together correctly without creating a complete mess. I'd be guessing about which biome to use and still match neighboring chunks. It seems like I need to intercept the process earlier, before it decides which biome to use.


So from there I have followed the trail to BiomeProvider#getBiomesForGeneration. But then I get lost. It seems to be getting a list of biomes from some GenLayer class that's supplied by GenLayer#initializeAllBiomeGenerators. That GenLayer class seems to be the first one in a list that initializeAllBiomeGenerators creates through some insane amount of other GenLayer calls. One of which is GenLayerBiome, which seems promising because it seems to be the only place that refers to Biome type (cool, warm, etc.).


That's as far as I've gotten in several hours of research.

Link to comment
Share on other sites

It really depends on how nicely you want to play with the other vanilla biomes. The biome dictionary is intended to allow you to add biomes that are categorized such that they will generate naturally in a way that "makes sense" in terms of whether they are dry, cold, etc. That is the best way to hook into the vanilla generation without getting caught up in the intricate generation details.


To add to the complication, I think there is some "abandoned" code. Like in the generateChunk() method near the end there is an local field for an array called abyte[] which seems to store all the biome IDs. however I don't see it ever being used.


But since you also have the Z position requirement, I would guess there is no good way to fully integrate that into the vanilla generation which uses some randomness and some categorization to blend things together. So I think there is nothing wrong with forcing it in the chunk generator setBlocksInChunk() method, although maybe it would feel more logical to do it in your BiomeProvider's getBiomesForGeneration() and I think also the getBiomes() methods. You just need to make sure that the array that tracks actual biome is also properly updated. 


So in summary since you want your biome to generate semi-naturally, I would make sure it is tagged properly in the biome manager and biome dictionary type registrations and then to control the Z I would check and/or force that in the biome provider.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

oh lord man, been a while since I worked on Minecraft.  Gave up modding because the source code kept changing too much and yadayada decided to work on my own game.

If it's still somewhat the same as when I was working on it,  I had to pretty much rewrite the ChunkProvider, and in the provideChunk function you can insert checks on height there.  I had a funky biome that would leave large areas of water so I wanted to rename these areas like "Lake" or something, so I inserted a check, if this biome, i'd do checks to see if there was water and if the water checked passed I changed that area to the biome Lake.  I started to get fed up with playing within the confines of the Minecraft generation rules after that and looking into my own engine but yeah it almost needs a whole new generation system to do sophisticated stuff without bogging down the code.     If you simply just want to do checks on which biome is next to which biome you need to start breaking down the GenLayer files.   I'd recc. playing around with it all anyway, I learned so much coool stuff messing around with it, like making nice beautiful huge rivers.

Link to comment
Share on other sites

I think I have figured this out. First I want to make it clear I wasn't doing this for a custom biome. My intent was to control where vanilla biomes appear, based on latitude (how far in the Z direction you go). I wanted hot biomes only to appear near Z=0, and get progressively cooler the further you go in either Z direction. I established an arbitrary "north/south pole" beyond which everything is cold and icy no matter how far you go.


I didn't try messing around with the BiomeProvider#getBiomesForGeneration or BiomeProvider#getBiomes since at that level we're working only with chunks. It seemed to difficult to me to change the biome for a given chunk and still ensure neighboring chunks also get updated with the correct biome, without doing some weird storing or searching of what biomes were assigned nearby. Perhaps I was wrong about that assumption, but in any case I felt the need to interrupt the regular biome choice much earlier in the process, during the GenLayer construction. I ended up doing a deep dive into world generation and learned a lot of stuff about how GenLayers work.


To solve this, I ended up creating my own world type and overrode WorldType#getBiomeLayer to supply a custom GenLayerBiome class instead of the vanilla GenLayerBiome. In the GenLayerBiome class, during the GenLayerBiome#getInts method, it checks to see which biome categories have been chosen (DESERT, WARM, COOL, or ICY). I jacked into the process there and overrode that method, where I checked the current Z position and swapped the category as desired. The tricky part was that the position values at this point are not chunk coordinates or block coordinates—they have been adjusted relative to biome size during the GenLayer process. Default biome size is 4, but I'm using a biome size of 6 (aka Large Biomes). It took me some time to figure out how to translate the position values into actual block coordinates so I could figure out a rough location on the Z axis.


I have only done a small amount of testing so far, but it's looking promising. I noticed a weird biome boundary at one point, where there was an unnatural cliff that hadn't been smoothed out. So I'm sure I will have tweaking to do. I may have to change something in the GenLayerEdge or GenLayerBiomeEdge classes. Not sure.

Edited by Daeruin
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.

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.

  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Minecraft opened, but when I went to create a new world I got another error. https://pastebin.com/mmdNztmW
    • java.lang.RuntimeException: Could not execute entrypoint stage 'main' due to errors, provided by 'terrablender'!     at net.fabricmc.loader.impl.FabricLoaderImpl.lambda$invokeEntrypoints$2(FabricLoaderImpl.java:388) ~[fabric-loader-0.15.11.jar:?]     at net.fabricmc.loader.impl.util.ExceptionUtil.gatherExceptions(ExceptionUtil.java:33) ~[fabric-loader-0.15.11.jar:?]     at net.fabricmc.loader.impl.FabricLoaderImpl.invokeEntrypoints(FabricLoaderImpl.java:386) ~[fabric-loader-0.15.11.jar:?]     at net.fabricmc.loader.impl.game.minecraft.Hooks.startServer(Hooks.java:63) ~[fabric-loader-0.15.11.jar:?]     at net.minecraft.server.Main.main(Main.java:112) ~[server-intermediary.jar:?]     at net.fabricmc.loader.impl.game.minecraft.MinecraftGameProvider.launch(MinecraftGameProvider.java:470) ~[fabric-loader-0.15.11.jar:?]     at net.fabricmc.loader.impl.launch.knot.Knot.launch(Knot.java:74) ~[fabric-loader-0.15.11.jar:?]     at net.fabricmc.loader.impl.launch.knot.KnotServer.main(KnotServer.java:23) ~[fabric-loader-0.15.11.jar:?]     at net.fabricmc.loader.impl.launch.server.FabricServerLauncher.main(FabricServerLauncher.java:69) ~[fabric-loader-0.15.11.jar:?] Caused by: java.lang.NoSuchFieldError: Class me.lortseam.completeconfig.data.BooleanEntry does not have member field 'boolean checkbox'     at me.lortseam.completeconfig.data.BooleanEntry.<init>(BooleanEntry.java:25) ~[completeconfig-base-2.5.0-cd5950f26b406f27.jar:?]     at me.lortseam.completeconfig.data.Entry.create(Entry.java:42) ~[completeconfig-base-2.5.0-cd5950f26b406f27.jar:?]     at me.lortseam.completeconfig.data.EntrySet.lambda$resolve$1(EntrySet.java:31) ~[completeconfig-base-2.5.0-cd5950f26b406f27.jar:?]     at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:212) ~[?:?]     at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:194) ~[?:?]     at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:1024) ~[?:?]     at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:556) ~[?:?]     at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:546) ~[?:?]     at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) ~[?:?]     at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) ~[?:?]     at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:265) ~[?:?]     at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:611) ~[?:?]     at me.lortseam.completeconfig.data.EntrySet.resolve(EntrySet.java:32) ~[completeconfig-base-2.5.0-cd5950f26b406f27.jar:?]     at me.lortseam.completeconfig.data.Parent.resolveContainer(Parent.java:58) ~[completeconfig-base-2.5.0-cd5950f26b406f27.jar:?]     at me.lortseam.completeconfig.data.Parent.resolve(Parent.java:110) ~[completeconfig-base-2.5.0-cd5950f26b406f27.jar:?]     at me.lortseam.completeconfig.data.Config.lambda$new$0(Config.java:51) ~[completeconfig-base-2.5.0-cd5950f26b406f27.jar:?]     at me.lortseam.completeconfig.data.Config.deserialize(Config.java:94) ~[completeconfig-base-2.5.0-cd5950f26b406f27.jar:?]     at me.lortseam.completeconfig.data.Config.load(Config.java:121) ~[completeconfig-base-2.5.0-cd5950f26b406f27.jar:?]     at io.github.uhq_games.regions_unexplored.RegionsUnexplored.onTerraBlenderInitialized(RegionsUnexplored.java:70) ~[RegionsUnexploredFabric-]     at terrablender.core.TerraBlenderFabric.lambda$onInitialize$0(TerraBlenderFabric.java:40) ~[TerraBlender-fabric-1.20.1-]     at java.util.ArrayList.forEach(ArrayList.java:1597) ~[?:?]     at terrablender.core.TerraBlenderFabric.onInitialize(TerraBlenderFabric.java:38) ~[TerraBlender-fabric-1.20.1-]     at net.fabricmc.loader.impl.FabricLoaderImpl.invokeEntrypoints(FabricLoaderImpl.java:384) ~[fabric-loader-0.15.11.jar:?]  
    • Hi, I have the oficial launcher using the version 1.21, and forge 51.0.13, as soon as I start the installation the games crashes and gives me "exit code: 1", I haven't put any mods yet in the folder. Its the second time that uninstall and install everything and nothing works, checket my graphics and they are updated. https://pastebin.com/STPgEiVs   thanks!
    • Ty very much it worked
    • no clue what is going on, you guys seem more knowledgeable than I am. So here's my log as well as my mod list. Error Folder On Google Drive  
  • Topics

  • Create New...

Important Information

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