GabeHasWon
Golem
2022 Update
With tModLoader now on 1.4, this tutorial is going to be inaccurate with regards to most things.
I will keep this up for posterity, and those few still on 1.3, but if you need a tutorial, please use the following:
tModLoader World Generation Tutorial
I hope this helped people while it was still useful. Good luck on whatever you're doing!
Hello everyone!
I am GabeHasWon, a fairly experienced programmer, one who happens to be very experienced in World Generation. As such, I feel that redoing this ancient tutorial that covers the basics of worldgen would be a useful thing to do. So, here I am.
Before I start on worldgen itself, I implore you to have the following basics down and good already:
* A good grasp of C# and the basic Terraria framework
* A good grasp of math, mostly algebra, trigonometry and geometry
* An incredible amount of patience - no matter how good you are, the majority of worldgen is changing minor things constantly, and you will have to make a ton of worlds in order to test your code
and finally,
* an understanding of logic, as you will need a very high amount of conditions, comparisons and adjustments to make your programming and generation work as intended
Preface
There's a lot of minutiae involved in world generation. They will constantly hang over you even as you do the most basic of structures, and are pivotal to understanding why your code does or does not work.
The most basic of these concepts are the coordinate system Terraria uses, where the position (0, 0) is the very top-left of the world. You can then use the public variables Main.maxTilesX and Main.maxTilesY in order to grab the width and height of the world, respectively.
When doing this, however, note that the playable world stops before the player can actually reach coordinate 0 on either axis - I've never tested, but the world stops scrolling maybe 40 or 50 tiles before it truly stops. Keep this in mind when you want to add stuff to the edges of the world, such as Ocean or Space content.
Refer to this for a much better visual representation of the heights in-world:
Another thing that is very important to note is generation order - in Terraria, the game uses a list of tasks called GenPasses that tell the world how to be generated in order. This is incredibly important to keep in mind - if you generate your, for example, ores too early, they could easily be overtaken by new generation that follows it. For example, I made a biome a while ago, and after a bit of testing, found that the dungeon or Lihahzrd Temple could override it, making it basically nonexistant. So, I had to move it forward in the gen list in order to not make my biome disappear.
You'll also find it easier to debug if you understand where your generation is placed in the list.
For further reference on vanilla generation steps' order, follow this list here.
Finally, something you will always have to keep in mind is that tiles are stored in a 2D array. The ramifications of that are as follows:
1. If you go outside of the bounds of the array (i.e. try to access the tile at (-1, 0)), it will crash or fail to generate;
2. If you are to use, for example, player position, you will need to divide player position by 16 in order to access the tile at the same position - for example, if I wanted to get the tile directly above the player, I would use the following code:
The same division operation would be conducted with projectiles, NPCs, dusts and gores.
3. These tile positions are also always an integer, and never a decimal of any sort. If you try to access the tile at 1.2f, 2, you will get an error.
4. Finally, every tile is always loaded in the world, but is only active when a tile is actually placed in-world - so, if you access an air tile, you might get a non-air type (i.e. Sand), but it will be empty.
Basics
So, with all of that aside, we can begin on the most simple methods and tools you can use to create or check or do whatever:
As for forced - I'd like to think that it forces the tile to be placed, but I don't often use this.
As for plr - I have no idea what this is. At all. Probably not important?
Finally,
If
If
And
This is very useful for checking a given tile's type, if it's active, or certain qualities about it.
Here's a more in depth explanation:
I think a better way to explain this is visual references:
For reference, every TileRunner there was exactly the following line:
Where STRENGTH = the strength value showcased.
and finally,
TileRunner is incredibly helpful for smaller scale chunks of a tile, such as ore deposits (ore being one of the most common uses for TileRunner), sand, dirt and stone chunks, and similar things. However, I'd recommend against using this for large scale biomes and structures, as it's really hard to use when you want to fill an area completely without being inefficient. Similarly, it's also very hard to control exactly how you want.
The only difference is what
Positioning
With all those methods in mind, the biggest problem I see for people doing generation is positions. Where do I put my structure to have it in <x> biome? Where's the sky? Where's the surface? These are all valid questions, which thankfully, are quite easy to solve - especially when you've been doing gen as long as I have.
You have the five major values -
As for X coordinates, it's a bit more ambiguous, with only four major values (that I've used) -
Of note is also the variable
Gen Passes, Cont.
Now for passes themselves.
GenPasses are, again, the way that Terraria handles world generation. It runs GenPass by GenPass in order, which builds the world piece by piece. These passes are as large as the whole dungeon, or as small as adding sand in early worldgen. It just matters on how you want to partition it.
GenPasses themselves end up being one of the most simple things to use, in all honesty.
Under the ModifyWorldGenTasks method, shown here,
you simply add your method or even code directly into a new task, as shown here,
and all you need to do is make a method called MyGenCode with a GenerationProgress parameter, such as this,
However, in most cases, you do not want to Add() your gen pass to the tasks list.
Usually, you want to insert your pass somewhere specifically, as described in the "Generation Order" subsection of the Preface. For example,
This would insert your generation right after the Shinies step, which is a step most often used to place ores.
Again, you can find the names of all vanilla passes here.
You can organize your worldgen into as many (or as little) genpasses as you want, but, I do recommend trying to keep them in different steps as you see fit. Especially for different biomes which could place in different places with different overlaps, sometimes you want a biome or structure to be placed in a different place compared to another biome you may add. Just make sure you understand where and when your biome is placed at all times, and you should be good.
Chests
(Suggested by @-=Soul=-)
Chests are naturally a very important part of designing a biome or structure and filling it with content.
Filling chests during worldgen (or even during play) is fairly simple:
PlaceChest is a method used during worldgen that, well, places a chest. It also returns the index of the Chest object in Main.chest that tile is associated with if the chest is placed successfully. If it's not placed successfully, it simply returns -1.
So, we can do this:
to check if, when we place down a chest, it is successful.
Then, within the
This would set the first item in the chest you've placed down to a single Bananarang.
If you want to increase the stack, simply do:
And boom, you have a stack of 20 Bananarangs.
Further manipulation of chests and their inventories just requires some logic and thought, so that about rounds this section up.
Notices & Afterword
Thanks for reading through this tutorial, unless you really wanted to read the afterword for no reason.
I'll be updating this tutorial as inspiration strikes me, or at user request (if possible), so feel free to respond to this thread with whatever you may want to know.
Now, remember:
With tModLoader now on 1.4, this tutorial is going to be inaccurate with regards to most things.
I will keep this up for posterity, and those few still on 1.3, but if you need a tutorial, please use the following:
tModLoader World Generation Tutorial
I hope this helped people while it was still useful. Good luck on whatever you're doing!
Hello everyone!
I am GabeHasWon, a fairly experienced programmer, one who happens to be very experienced in World Generation. As such, I feel that redoing this ancient tutorial that covers the basics of worldgen would be a useful thing to do. So, here I am.
Before I start on worldgen itself, I implore you to have the following basics down and good already:
* A good grasp of C# and the basic Terraria framework
* A good grasp of math, mostly algebra, trigonometry and geometry
* An incredible amount of patience - no matter how good you are, the majority of worldgen is changing minor things constantly, and you will have to make a ton of worlds in order to test your code
and finally,
* an understanding of logic, as you will need a very high amount of conditions, comparisons and adjustments to make your programming and generation work as intended
Preface
There's a lot of minutiae involved in world generation. They will constantly hang over you even as you do the most basic of structures, and are pivotal to understanding why your code does or does not work.
The most basic of these concepts are the coordinate system Terraria uses, where the position (0, 0) is the very top-left of the world. You can then use the public variables Main.maxTilesX and Main.maxTilesY in order to grab the width and height of the world, respectively.
When doing this, however, note that the playable world stops before the player can actually reach coordinate 0 on either axis - I've never tested, but the world stops scrolling maybe 40 or 50 tiles before it truly stops. Keep this in mind when you want to add stuff to the edges of the world, such as Ocean or Space content.
Refer to this for a much better visual representation of the heights in-world:
Another thing that is very important to note is generation order - in Terraria, the game uses a list of tasks called GenPasses that tell the world how to be generated in order. This is incredibly important to keep in mind - if you generate your, for example, ores too early, they could easily be overtaken by new generation that follows it. For example, I made a biome a while ago, and after a bit of testing, found that the dungeon or Lihahzrd Temple could override it, making it basically nonexistant. So, I had to move it forward in the gen list in order to not make my biome disappear.
You'll also find it easier to debug if you understand where your generation is placed in the list.
For further reference on vanilla generation steps' order, follow this list here.
Finally, something you will always have to keep in mind is that tiles are stored in a 2D array. The ramifications of that are as follows:
1. If you go outside of the bounds of the array (i.e. try to access the tile at (-1, 0)), it will crash or fail to generate;
2. If you are to use, for example, player position, you will need to divide player position by 16 in order to access the tile at the same position - for example, if I wanted to get the tile directly above the player, I would use the following code:
Framing.GetTileSafely((int)(player.position.X / 16f), (int)(player.position.Y / 16f) - 1)
The same division operation would be conducted with projectiles, NPCs, dusts and gores.
3. These tile positions are also always an integer, and never a decimal of any sort. If you try to access the tile at 1.2f, 2, you will get an error.
4. Finally, every tile is always loaded in the world, but is only active when a tile is actually placed in-world - so, if you access an air tile, you might get a non-air type (i.e. Sand), but it will be empty.
Basics
So, with all of that aside, we can begin on the most simple methods and tools you can use to create or check or do whatever:
- WorldGen.PlaceTile(int i, int j, int type, bool mute = false, bool forced = false, int plr = -1, int style = 0)
i, j
, of type type
, plays a sound if mute
is false.As for forced - I'd like to think that it forces the tile to be placed, but I don't often use this.
As for plr - I have no idea what this is. At all. Probably not important?
Finally,
style
is tough to explain - it is used to show alternate versions of a single tile. I'll explain this a bit more with PlaceObject.- WorldGen.KillTile(int i, int j, bool fail= false, bool effectOnly = false, bool noItem = false)
i, j
.If
fail
is true, the tile is NOT removed. This is used for when you mine a pickaxe but it needs multiple hits, for example.If
effectOnly
is true, the tile ONLY spawns dust, but does not break. Usually in tandem with fail. For example, mining a tile with too low of pickaxe power.And
noItem
is simple, does not drop an item when the tile is killed.- Framing.GetTileSafely(int i, int j)
This is very useful for checking a given tile's type, if it's active, or certain qualities about it.
- WorldGen.TileRunner(int i, int j, int strength, int steps, int type, bool addTile = false, float speedX = 0, float speedY = 0, bool noYChange = false, bool overRide = true)
Here's a more in depth explanation:
i
and j
are the position of the TileRunner. Again, this is in tile position. so you'd have to divide by 16 if you want to use a player or npc position to gen something.strength
is how large the resulting chunk is - the "radius" in a way.I think a better way to explain this is visual references:
Three different examples of a TileRunner with a strength of 2:
Three different examples of a TileRunner with a strength of 4:
Three different examples of a TileRunner with a strength of 8:
Two different examples of a TileRunner with a strength of 16:
And finally, two different examples of a TileRunner with a strength of 32:
C#:
WorldGen.TileRunner((int)(Main.MouseWorld.X / 16f), (int)(Main.MouseWorld.Y / 16f), STRENGTH, 5, TileID.Dirt, true, 0, 0, false, true);
step
is a bit more confusing to me - as far as I'm aware, it's the amount of repeats, of loops, you do on this TileRunner call. This you to place stuff in a line if need be using speedX and speedY, explained after addTile.addTile
tells the TileRunner if you want to add tiles or not. If you set this to true, it will place new tiles. If not, it will only replace old tiles, as long as overRide is set to true.speedX
and speedY
refer to the displacement of the new chunk made after a loop. For example, if I have a TileRunner of any size, in any position, with 3 steps and a speedX of 5 and a speedY of 0, it will place 3 chunks, each 5 blocks apart, starting from the original position (i, j) and going right. Alternatively, if I set speedX to a negative, it'll start at (i, j) and go left. Same principle applies to speedY; just that negative speedY goes up, and positive speedY goes down, respective to (i, j). This might be a bit of a wordy explanation, but it should make sense if you mess around with it a tad.noYChange
is...odd. I've not tested it ever, but I'm to guess it just makes the TileRunner ignore speedY. I dunno. Just keep this to false I guess.and finally,
overRide
. This, when true, replaces existing tiles with the tile of your type if possible. For example, if I'm placing my ore, BananaOre, I would want to set overRide to true so it'd spawn in stone and mud and dirt and stuff. Set to false when you only want to add tiles.TileRunner is incredibly helpful for smaller scale chunks of a tile, such as ore deposits (ore being one of the most common uses for TileRunner), sand, dirt and stone chunks, and similar things. However, I'd recommend against using this for large scale biomes and structures, as it's really hard to use when you want to fill an area completely without being inefficient. Similarly, it's also very hard to control exactly how you want.
- WorldGen.digTunnel(int i, int j, float xDir, float yDir, int Steps, int Size, bool Wet = false)
The only difference is what
Wet
does; that places water in the tunnel it digs. Simple enough.Positioning
With all those methods in mind, the biggest problem I see for people doing generation is positions. Where do I put my structure to have it in <x> biome? Where's the sky? Where's the surface? These are all valid questions, which thankfully, are quite easy to solve - especially when you've been doing gen as long as I have.
You have the five major values -
- 0, the very top of the world;
- Main.worldSurface, the surface of the world and the point at which going below is considered "underground";
- Main.rockLayer, the deeper caves of the world and the point at which going below is considered "caverns";
- Main.maxTilesY - 200, or the Underworld layer, at which point going below means you're in the Underworld;
- and finally Main.maxTilesY, the bottom of the world.
As for X coordinates, it's a bit more ambiguous, with only four major values (that I've used) -
- 0, the very left of the world;
- Main.maxTilesX / 2, the centre of the world;
- Main.maxTilesX, the very right of the world;
- and finally, Main.dungeonX. This value can be to the left of or to the right of the centre of the world, which allows you to know the position of the snow and jungle biomes. If
Main.dungeonX
is LESS THANMain.maxTilesX / 2
, the snow biome and the dungeon are to the left of spawn. Otherwise, they are to the right of spawn. Note that dungeonX may not be set if used before the Dungeon generation step.
Of note is also the variable
WorldGen.UndergroundDesertLocation
, a Rectangle. This stores the top-left corner of the Underground Desert through WorldGen.UndergroundDesertLocation.Location
, and the size through WorldGen.UndergroundDesertLocation.Size()
. This is useful in situations like Calamity's Sunken Sea, or Starlight River's Vitric Desert biomes.Gen Passes, Cont.
Now for passes themselves.
GenPasses are, again, the way that Terraria handles world generation. It runs GenPass by GenPass in order, which builds the world piece by piece. These passes are as large as the whole dungeon, or as small as adding sand in early worldgen. It just matters on how you want to partition it.
GenPasses themselves end up being one of the most simple things to use, in all honesty.
Under the ModifyWorldGenTasks method, shown here,
C#:
public override void ModifyWorldGenTasks(List<GenPass> tasks, ref float totalWeight)
C#:
tasks.Add(new PassLegacy("My Custom Generation", MyGenCode));
C#:
public void MyGenCode(GenerationProgress p)
However, in most cases, you do not want to Add() your gen pass to the tasks list.
Usually, you want to insert your pass somewhere specifically, as described in the "Generation Order" subsection of the Preface. For example,
Code:
int shiniesIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Shinies"));
if (shiniesIndex != -1)
tasks.Insert(shiniesIndex + 1, new PassLegacy("MyGenPass", MyGenPass));
Again, you can find the names of all vanilla passes here.
You can organize your worldgen into as many (or as little) genpasses as you want, but, I do recommend trying to keep them in different steps as you see fit. Especially for different biomes which could place in different places with different overlaps, sometimes you want a biome or structure to be placed in a different place compared to another biome you may add. Just make sure you understand where and when your biome is placed at all times, and you should be good.
Chests
(Suggested by @-=Soul=-)
Chests are naturally a very important part of designing a biome or structure and filling it with content.
Filling chests during worldgen (or even during play) is fairly simple:
C#:
WorldGen.PlaceChest(x, y, type, notNearOtherChests, style)
So, we can do this:
C#:
int ChestIndex = WorldGen.PlaceChest(x, y, (ushort)type, false, style);
if (ChestIndex != -1)
Then, within the
if
statement, we can do something like this:
C#:
Main.chest[ChestIndex].item[0].SetDefaults(ItemID.Bananarang);
If you want to increase the stack, simply do:
C#:
Main.chest[ChestIndex].item[0].stack = 20;
Further manipulation of chests and their inventories just requires some logic and thought, so that about rounds this section up.
Notices & Afterword
Thanks for reading through this tutorial, unless you really wanted to read the afterword for no reason.
I'll be updating this tutorial as inspiration strikes me, or at user request (if possible), so feel free to respond to this thread with whatever you may want to know.
Now, remember:
- I will not program your biome or structure for you.
- I will not usually go out of my way to give you very specific information on how to generate or implement something - I'd like to keep this tutorial relatively general, as WorldGen is an art that I cannot really explain without reducing it's utility to the general public. However, that does not mean I will not sometimes find something interesting enough to tackle regardless.
- I will not help with visual or texture-based errors; this is to be a programming-based tutorial and I'd feel that trying to add spriting to it would be difficult to balance.
- I will add FAQ if needed.
- I will always further remind you that this takes patience - for my mod, I've generated well over five hundred worlds and I'm guessing I have a couple hundred more to go.
- I am just one lad, one man, and I can only do so much.
- Finally, if something doesn't work, try to work it out a bit before coming here for help. Some problems are easily solved after a bit of thought, even if it seems difficult for a while. I, for one, know I've been stuck on many a problem despite them being as simple as a single number that's too high or the lack of a method call.
Note from 2021 Gabe: This tutorial is very outdated, and uses only the most basic of my knowledge. It also hasn't been rewritten in 5 years, so don't expect anything great here. I just wanted to keep it on this post in case people find that parts of this are missing from the main post while I redo it.
2016 Gabe:
Hello people!
It seems that there has been an explosion of World Generation in mods, and, well, I thought I'd throw whatever I can in.
Note: This tutorial is a bit complicated. You should know how to at least make a basic NPC before you read this. Or be crazy and read it anyways.
So, here will be a basic tutorial on how to make simple lines/passageways, blobs of block, or pools/mini biomes, which will come later.
Ok, let's start off now
First off, it'd be useful to have something to base off, so ExampleMod has a decent example (duh) with it's Well. Use that and tinker for a bit, change the water to dirt, as to get a feel for it.
Basic Blob Making
Then, once you're done turning a well into a blob, we can begin.
Go into your ModWorld.cs file add a method called ModifyWorldGenTasks()
Obviously, put {} around it. Now, let's start with a blobbecause I'm lazy.
That should place a blob of dirt above the player. You can replace the TileID with any other ID or mod.TileType("") if you wish.
That is the simplest of the things you can possibly do.
I'll keep the above code for future inserts, so I don't have to re-write it over. And over. And over again
So when I say something of this sort: Add code into your existing method, it means add the code into the Dirt Blob thing
Making a Line
Now for something a bit less...blobby.
I personally did this in a method as to make it easier to randomize, but you may do whatever you want.
So, there is a method in WorldGen called PlaceTile. It's a more precise way of using TileRunner.
So, we use a for loop to make a straight line, like this:
If you add that, it should make a 10 block long iron ore thing. I might've gotten the TileID wrong, but you get the point.
Now let's get to the really fun stuff.
Overriding a Biome
Are you tired of having Jungles in your world? Don't Jungle Bats bother you when you're setting up your mud hut? Well, I got the fix for you! Code. yay?
Anyways, yes, you can remove biomes and put a bunch of whatever there.
So now you should have no jungle (if I remembered the name correctly) and an extra blob of dirt, but below you. Do not put this is the same code block (These: { }) as the previous dirt blob, that will give an error.
Tested: it works with any proper gen step.
How to Place Multi blocks
As shown above, people want to know how to place something such as a Table or Chair.
So, you have to use the WorldGen.PlaceTile method.
This, without testing, should place an Example Chair 10 blocks away from the player.
Placing a Chest
I've barely explored this concept; you could make a "starter chest" near spawn with some good lewt. Or, just a Meowmere. Either work.
So, you can't place chests with PlaceObject (for some reason) so you need PlaceChest. Code shown below.
So, basic explanation of what those do: X and Y is duh. Type is what chest type. notNearOtherChests makes it so you can't place a chest there if it's near another. Style is what frame.X is should be at, used for placing locked chests.
So, just do
for a chest to appear next to the player. Not sure what chest though, the chest tilesheet is the longest thing ever. (Needs testing)
Making a Meteor-like biome
So, here is a method that makes a 'comet' out of any pre-hardmode ore, except Demonite, Hellstone and Crimtane. It places this anywhere above ground, with it initially spawning above the world, and doesn't place until it hits a block. This method won't do anything alone, though, you'll place it in the Kill method of a projectile, which is easiest. The projectile should call Kill OnTileCollide(). Code:
That should have a 0.1% chance to spawn every frame.
Have fun!
Floating Islands
Let's spam us some candy cane w/ red team block floating islands.
As suggested by @Jenosis
REWRITTEN:
It's only clouds now, but the generation & code is much smoother.
topCentre is the position of the, well, top and centre tile of the island. It'll be slightly under the top (around 4 blocks on a 50 tile wide island), but point stands.
size is the width. Not much more to say.
type is the TileID of the island; in the following screenshot, it's TileID.Clouds.
I am willing to create a more functional floating island with dirt, grass, and the like, but for now this should be enough. It's much more efficient too.
Change any of the TileIDs to your liking. Have fun!
Placing a Tree, and growing the Tree
This one is pretty simple, really. I'll just slap in some code and done
do that as a base. Make it 3 wide, so the tree will go properly.
Then:
This will grow the MagicSapling if it can. Otherwise, it'll simply place a sapling.
Notify me on this thread/my profile page if this doesn't work. Thanks!
Placing Walls
It's basically the same as placing a tile. But with walls. Woah.
Here's two:
or
Simple enough
Changing Tile Slopes
Also simple.
From what I know, it goes from 0 to 12. Tell me if I'm wrong.
TileIDs can be found here: tModLoader/tModLoader
Some useful (ints) things for WorldGen are Main.maxTilesY, same thing but with X, Main.spawnTileY, and X.
Main.spawnTileX +/- 300-400 is the Snow/Desert biome. Main.maxTilesY - 200 is the top of the Underworld.
The amount of derps done here: 11 so far.
I will expand this upon user request, though I won't do your WorldGen for you.
Anyways, that'll be it for now. Leave any comments/questions/suggestions below
Credits
Thanks to @Graydee for being helpful with worldgen on occasion
Thanks to @EchoNex for the first WorldGen code he gave me.
Thanks to @jopojelly for random helps
I request that anyone who uses this tutorial and publishes it in any way, Mod Browser or not, gives me any sort of credit. Either it be a link to this thread, a link to me, a simple "thanks to gabe for some worldgen stuff", please do it
2016 Gabe:
Hello people!
It seems that there has been an explosion of World Generation in mods, and, well, I thought I'd throw whatever I can in.
Note: This tutorial is a bit complicated. You should know how to at least make a basic NPC before you read this. Or be crazy and read it anyways.
So, here will be a basic tutorial on how to make simple lines/passageways, blobs of block, or pools/mini biomes, which will come later.
Ok, let's start off now
First off, it'd be useful to have something to base off, so ExampleMod has a decent example (duh) with it's Well. Use that and tinker for a bit, change the water to dirt, as to get a feel for it.
Basic Blob Making
Then, once you're done turning a well into a blob, we can begin.
Go into your ModWorld.cs file add a method called ModifyWorldGenTasks()
The full method is here:
Code:
public override void ModifyWorldGenTasks(List<GenPass> tasks, ref float totalWeight)
Obviously, put {} around it. Now, let's start with a blob
Code:
public override void ModifyWorldGenTasks(List<GenPass> tasks, ref float totalWeight)
{
int genIndex = tasks.FindIndex(genpass => genpass.Name.Equals("Micro Biomes"));
tasks.Insert(genIndex + 1, new PassLegacy("Dirt Blob", delegate (GenerationProgress progress)
{
WorldGen.TileRunner(Main.spawnTileX, Main.spawnTileY - 46, 6, Main.rand.Next(1, 3), TileID.Dirt, true, 0f, 0f, true, true);
}));
}
Here's an explanation of what's in the TileRunner method.
So, I and J is X and Y, respectively. Strength decides how big it is (I can't understand the code enough to give a presise measurement.) Type is the type of tile, in TileID, int, or mod.tiletype. Add Tile checks if you're adding tiles or replacing them. SpeedX and Y sets the direction it goes is (also don't understand the code). noYChange is just that. It doesn't change Y. overRide means it can override other tiles.
Code:
TileRunner(int i, int j, double strength, int steps, int type, bool addTile = false, float speedX = 0f, float speedY = 0f, bool noYChange = false, bool overRide = true)
That should place a blob of dirt above the player. You can replace the TileID with any other ID or mod.TileType("") if you wish.
That is the simplest of the things you can possibly do.
I'll keep the above code for future inserts, so I don't have to re-write it over. And over. And over again
So when I say something of this sort: Add code into your existing method, it means add the code into the Dirt Blob thing
Making a Line
Now for something a bit less...blobby.
I personally did this in a method as to make it easier to randomize, but you may do whatever you want.
So, there is a method in WorldGen called PlaceTile. It's a more precise way of using TileRunner.
Here is the method.
Please note that it places in tile positions, so if you want to place it in game at, say, npc.position.X, do npc.position.X / 16.
Code:
WorldGen.PlaceTile(int X, int Y, int TileType);
So, we use a for loop to make a straight line, like this:
Code:
for (int i = 0; i < 10; i++)
{
WorldGen.PlaceTile(Main.spawnTileX + i, Main.spawnTileY - 30, TileID.Iron);
}
If you add that, it should make a 10 block long iron ore thing. I might've gotten the TileID wrong, but you get the point.
Now let's get to the really fun stuff.
Overriding a Biome
Are you tired of having Jungles in your world? Don't Jungle Bats bother you when you're setting up your mud hut? Well, I got the fix for you! Code. yay?
Anyways, yes, you can remove biomes and put a bunch of whatever there.
Code:
int jungleGen = tasks.FindIndex(genpass => genpass.Name.Equals("Jungle"));
tasks[jungleGen] = new PassLegacy("More Dirt Blobs", delegate (GenerationProgress progress)
{
WorldGen.TileRunner(Main.spawnTileX, Main.spawnTileY + 12, 6, Main.rand.Next(1, 3), TileID.Dirt, true, 0f, 0f, true, true);
});
Tested: it works with any proper gen step.
How to Place Multi blocks
can you post how to:
specify where in the world
how to prevent a certain world gen task
how to spawn multi tile blocks (chests tables doors etc)
EDIT: also, how to spawn structures with multi tile blocks
As shown above, people want to know how to place something such as a Table or Chair.
So, you have to use the WorldGen.PlaceTile method.
Code:
//PlaceObject(int x, int y, int type, bool mute = false, int style = 0, int alternate = 0, int random = -1, int direction = -1)[code] That's an explanation of the args.[/SPOILER]
So, this will place a modded chair in the X and Y:
[code] WorldGen.PlaceObject(Main.spawnTileX + 10, Main.spawnTileY, mod.TileType("ExampleChair"), false, 0, 0, -1, 1);
Placing a Chest
I've barely explored this concept; you could make a "starter chest" near spawn with some good lewt. Or, just a Meowmere. Either work.
So, you can't place chests with PlaceObject (for some reason) so you need PlaceChest. Code shown below.
Code:
WorldGen.PlaceChest(int X, int Y, int type, bool noNearOtherChests = false, int style = 0);
So, just do
Code:
WorldGen.PlaceChest(Main.spawnTileX - 10, Main.spawnTileY, 21, false, 2);
Making a Meteor-like biome
Easy enoughSadCube said:Hey, nice tutorial! But how to make something like meteorite biome?
Code:
public void OreComet()
{
int x = Main.rand.Next(0, Main.maxTilesX);
int y = Main.worldSurface - 200;
int[] tileIDs = { 6, 7, 8, 9 , 166, 167, 168, 169};
if (Main.tile[x, y].type <= -1)
{
y++;
}
else
{
WorldGen.TileRunner(x, y, 2, 4, tileIDs[Main.rand.Next(tileIDs.Length)], false, 0f, 0f, true, true);
return;
}
}
Code:
public override void Kill()
{
OreComet();
}
Have fun!
Floating Islands
Let's spam us some candy cane w/ red team block floating islands.
As suggested by @Jenosis
REWRITTEN:
It's only clouds now, but the generation & code is much smoother.
Code:
private void GenIsland(Point topCentre, int size, int type)
{
for (int i = -size / 2; i < size / 2; ++i)
{
int repY = (size / 2) - (Math.Abs(i));
int offset = repY / 5;
repY += WorldGen.genRand.Next(4);
for (int j = -offset; j < repY; ++j)
{
WorldGen.PlaceTile(topCentre.X + i, topCentre.Y + j, type);
}
}
}
size is the width. Not much more to say.
type is the TileID of the island; in the following screenshot, it's TileID.Clouds.
I am willing to create a more functional floating island with dirt, grass, and the like, but for now this should be enough. It's much more efficient too.
Change any of the TileIDs to your liking. Have fun!
Placing a Tree, and growing the Tree
This one is pretty simple, really. I'll just slap in some code and done
Code:
WorldGen.PlaceTile(X, Y, TileID.Dirt);
Then:
Code:
WorldGen.PlaceObject(X, Y - 1, mod.TileType("MagicSapling));
WorldGen.GrowTree(X, Y - 1);
Notify me on this thread/my profile page if this doesn't work. Thanks!
Placing Walls
It's basically the same as placing a tile. But with walls. Woah.
Here's two:
Code:
WorldGen.PlaceTile(int i, int j, int type)
Code:
Main.tile[i, j].wall = WallID.MudUnsafe;
Changing Tile Slopes
Also simple.
Code:
Main.tile[i, j].slope(0);
TileIDs can be found here: tModLoader/tModLoader
Some useful (ints) things for WorldGen are Main.maxTilesY, same thing but with X, Main.spawnTileY, and X.
Main.spawnTileX +/- 300-400 is the Snow/Desert biome. Main.maxTilesY - 200 is the top of the Underworld.
The amount of derps done here: 11 so far.
I will expand this upon user request, though I won't do your WorldGen for you.
Anyways, that'll be it for now. Leave any comments/questions/suggestions below
Credits
Thanks to @Graydee for being helpful with worldgen on occasion
Thanks to @EchoNex for the first WorldGen code he gave me.
Thanks to @jopojelly for random helps
I request that anyone who uses this tutorial and publishes it in any way, Mod Browser or not, gives me any sort of credit. Either it be a link to this thread, a link to me, a simple "thanks to gabe for some worldgen stuff", please do it
Last edited: