• Mods are now organized as resources. Use the Mods link above to browse for or submit a mod, tool, or prefab.

    The TFP Official Modding Forum Policy establishes the rules and guidelines for mod creators and mod users.

Custom River Stamps

Just an update to correct an earlier assumption that I made about the raw file format:

After using an analysis script on various vanilla stamps (canyon, crater, etc) I've discovered that channel 0 in the raw file is indeed unused in canyon stamps, but it appears to definitely get some use in other types of stamps.

With canyon stamps, any value higher than 0 inside channel 0 causes a blanket "uplift" affect to the stamp. It acts kinda like an alpha offset mask to the heightmap data stored in channel 1, which raises your whole canyon stamp straight up out of the ground by whatever value (or array of values) you put in channel 0. That's not really something you want to ever happen with a canyon, so it makes sense that channel 0 remains unused in that type of stamp.

I have yet to dig into how exactly it's used in craters, hills, mountains, etc. But once this is all figured out, modders should easily be able to add any kind of terrain feature they want to the vanilla random world generator without ever having to write a single line of xml or c#.
 
Last edited:
Inspired by something @zztong was doing with craters, I started working on a python script to procedurally generate raw stamps. Rivers are WAY too complicated to start out with -- especially since I've never worked with procgen algorithms before in my life. So I decided to try out canyons first because that's the type of raw file I know the most about, and because canyons only use 1 channel from the raw file. So it's low-hanging fruit. Zztong has already done some really nice tradional canyons, so I thought I'd do something a little different.

Here are the results of my first attempt at a sink hole stamp:

20250809211921_1.jpg
20250809205900_1.jpg
20250809210117_1.jpg
20250809201406_1.jpg
20250809202537_1.jpg
20250809205530_1.jpg
20250809205424_1.jpg
20250809203341_1.jpg
 
I started working on a python script to procedurally generate raw stamps.

Those canyons I made years ago were basically inverted mountain ranges from around the world. I don't remember how I made them.

Something that becomes possible with a script is that a person could generate some custom temporary stamps prior to making a world, such that worlds become even more unique. The script could accept parameters describing different desired attributes, for instance, the max height of mountains.
 
Those canyons I made years ago were basically inverted mountain ranges from around the world. I don't remember how I made them.

Something that becomes possible with a script is that a person could generate some custom temporary stamps prior to making a world, such that worlds become even more unique. The script could accept parameters describing different desired attributes, for instance, the max height of mountains.

Oh, absolutely. The scripts I've been working are designed with a config block at the top with a number of variables that act as "levers" so that I can easily tweak things like noise amount, erosion intensity, etc. Those variables could easily be set by RNG which would give you random stamps every time you run the script. You wouldn't even have to shut down the game to rerun your scripts, because the worldgen re-reads the stamps every time you hit the generate button in the map menu. So that's a pretty awesome idea!

Btw, after posting these pics, I realized my original rim_falloff_width value wasn't really doing anything inside the sinkhole rim -- it only eroded the top of the canyon and surrounding terrain. So to make it look better, I split that into two separate variables (and associated code): rim_falloff_inner and rim_falloff_outer. That totally got rid of some of the weird artifacts you might have noticed in the above pictures. Here are a couple examples of the new sinkhole version. I made the sinkhole MUCH deeper this time for debugging purposes...

20250810013819_1.jpg
20250810013907_1.jpg

20250810015148_1.jpg

At this depth the "sinkhole" actually looks more like a bona fide canyon, which isn't really what I'm going for. But it shows the improvements I've made to the stamp walls.
 
Here's a really deep sinkhole in the forest biome. Managed to get one without water in the bottom!

20250810145410_1.jpg

My next goal is to add some procedural perturbations to the canyon rim/walls. Currently the stamp is just sorta egg-shaped with smooth, arched lines. It looks okay I guess at ground level, but when you're up on a mountain or in the air looking down, it looks like a giant egg fell from space and left an egg-shaped hole in the world. 🥚 Not ideal.
 
Another reason why you want to break up any smooth, curving lines in your original shape... weird banding and moire-like patterns can form:
20250810155207_1.jpg
 
Okay, figured out what I did wrong. What I'm trying to do is take a circle or ellipse and use a procedural perlin / simplex algorithm to turn a smooth circle into a rough, jagged, natural-looking circular shape. I accidentally applied that algorithm to the entire stamp instead of just the canyon rim. Oops.

Here's the fixed version. All shots are from the ground, because the pattern is too fine to notice from high up in the air:

20250811040202_1.jpg20250811040117_1.jpg
20250811042140_1.jpg
20250811042408_1.jpg

Same stamp, different biomes. The detail this added to the canyon walls looks good but is WAY too fine for my purposes. I'm trying to create really large chunks of jagged rockface in order to break up that perfectly circular canyon rim. So right now I'm splitting my function into two separate passes -- a low frequency pass to REALLY break up that canyon wall into large chunks, and a high frequency pass like you see in these screenshots to add more up close detail and "texture" to the canyon walls.

Gotta say, I've wanted to play around with procgen algorithms for years but always felt intimidated by the math. But the noise 1.2.2 library for python makes this stuff doable even for a hobby coder like me.
 
That was a much tougher job than I expected. But I now have the procedural algorithm both eroding the canyon walls AND reshaping them. The canyon begins as a simple ellipse drawn on an x,z plane, but then the procgen warps and fractures and erodes it into a more natural shape. It uses a random seed for the procgen, so every canyon can be unique. Some pics:

20250812004831_1.jpg
20250812005355_1.jpg

20250812005224_1.jpg
20250812005417_1.jpg
20250812005444_1.jpg
20250812005503_1.jpg

The roughness, erosion and canyon wall deformations are all fully adjustable with frequency, amplitude and octave control for both the low pass (overall shape) and the high pass (fine detail). At this stage it's just a matter of playing with the settings and finding some good default values.
 
Still working on this. I've learned quite a bit -- not just about procedural generation, but also the difficulties involved in creating 2D heightmaps so that they work well as stamps in a voxel-based engine.

The first big lesson I learned was that we only have a limited amount of control over how a stamp is used by the game. You can create a flawless 2D heightmap, but you have no control over how the engine is going to transform that heightmap into a 3D voxel structure. This caused lots of problems when I first started trying to do sheer cliffs and steep slopes.

When dealing with any sort of sheer drop, there is almost nothing you can do to influence how a vertical wall of terrain is going to look because you can't control anything volumetrically inside that vertical space. You have some control over the x,z pixels that comprise an overhead view of that sheer cliff's edge (ie, your 2D heightmap), but that's it. So it took me awhile to understand that a lot of the ugly banding artifacts I was seeing on very steep (but not totally vertical) walls was something I couldn't do anything about. I wasted a lot of time trying to solve that issue, only to realize that the only solution is to completely avoid creating slopes at those particular angles.

Once slopes get down to about 60 or 70 degrees, you have the ability to take more active control of them because, as the slope angle decreases and gets shallower, its perceptual surface volume increases from an overhead 2D perspective. In other words, shallow slopes have more visible pixels than steep slopes in a heightmap.

Another giant nightmare I dealt with involved artifact suppression; if you're seeing long rows of ugly spikes and spires ingame -- then there's a good chance that the artifacts on the stamp aren't spikes at all. You can research all the spike suppression algorithms you want, but they won't do any good if the artifact that's ACTUALLY in your heightmap is a long, 1-pixel wide, thin wall that the game only interprets as spikes and spires.

So anyway... after lots of trial and error and debugging, my stamp generator is now to the point where I've started adding extras like procedurally generated erosion channels and rim collapse zones in order to create natural-looking entrance points for really deep terrain features, such as canyons and sinkholes.

20250827225742_1.jpg20250827230022_1.jpg
20250827230056_1.jpg
20250827230212_1.jpg
20250827230720_1.jpg
20250827231227_1.jpg

Same stamp, different biomes. Right now the stamp gen uses separate seeds and other values for the stamp silhouette, floor noise, erosion patterns, number & size of entry paths, and cragginess of walls. Hopefully soon I'll be able to add more realistic fractal patterns and then finally get back to rivers again.
 
Yeah, those are looking good. Adds some much needed variety. The forest one in that last post with the cliff edge gives me ARK vibes. Prime base building location. Haha.
 
Back
Top