Mods / Algernon's Terrain Sampler Lib

Tags:
Library
Author:
Algernon
Side:
Both
Created:
Mar 25th at 11:15 AM
Last modified:
Apr 27th at 9:19 AM
Downloads:
5970
Follow Unfollow 225
Latest release (for Vintage Story 1.22.0, potentially outdated):
algernonsterrainsampler_1.2.1.zip  1-click install

A simple tool for efficiently getting the generated terrain's height anywhere in the world.

Even if the chunk hasn't been created or even loaded yet, this still works. You could sample 2 billion blocks away as long as it's within the world boundary.

 

Use /terrainsampler columnheight ingame to test it out.

 

To get this function working in your mod, reflect this mod's assembly, then reflect sampleHeight as shown here:

foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
    Type modType = assembly.GetType("AlgernonsTerrainSampler.TerrainSamplerMod");
    if (modType == null)
        continue;

    PropertyInfo instanceProperty = modType.GetProperty("Instance", BindingFlags.Public | BindingFlags.Static);
    MethodInfo getHeightMethod = modType.GetMethod("GetBlockColumnHeight", BindingFlags.Public | BindingFlags.Instance, null, [typeof(int), typeof(int)], null);
    if (instanceProperty == null || getHeightMethod == null)
        break;

    object instance = instanceProperty.GetValue(null);
    int sampleHeight(int blockX, int blockZ) => (int)getHeightMethod.Invoke(instance, [blockX, blockZ]);

Then give the height sampler delegate (sampleHeight) to your code that uses terrain height samples.

 

The terrain generation usually changes every major update, so don't use this on a different major version than the one it's made for.

 

This tool was made to help Farseer and the other two LOD mods in development, but you could use it for a lot of different things.

Originally, this came from the Watersheds mod. Terrain sampling is the core foundation of what enabled me to create terrain-respecting streams.

Here are some mod ideas you could make from terrain sampling:

  • Terrain erosion effects
  • Rain shadows
  • Realistic wind flows
  • Very long roads that respect the terrain, maybe between story structures
  • Very long pathfinding routes, maybe for animal herds or trader routes
  • Rivers and streams
  • Realistic pond, lake, and spring placement
  • Realistic snow depths (unsheltered areas have less snow, sheltered has more snow)
  • Realistic fog areas (in sheltered areas)
  • Groundwater and aquifers (a basic groundwater system is in Watersheds)
  • Strategic/believable placement of ruins/structures/villages

Mod Version Mod IdentifierFor Game version Downloads Released Changelog Download 1-click mod install*
1.2.1 algernonsterrainsampler 5357 Apr 27th at 9:19 AM algernonsterrainsampler_1.2.1.zip 1-click install

Fix an intermittent case where this isn't compatible with watersheds

1.2.0 algernonsterrainsampler 539 Apr 15th at 8:01 PM algernonsterrainsampler_1.2.0.zip 1-click install

update to 1.22 rc8

1.0.1 algernonsterrainsampler
1.21.0 - 1.21.6
74 Mar 26th at 12:05 PM Empty algernonsterrainsampler_1.0.1.zip 1-click install
1.0.0 algernonsterrainsampler
1.21.0 - 1.21.6
0 Mar 26th at 11:18 AM Release Retracted

Retraction Reason:

One last change

Changelog:


32 Comments (oldest first | newest first) (threaded | flat)

Larrian, 2 days ago

What's the time complexity of this tool? Playing around with it, it seems to drastically slow when sampling outside of nearby chunks, but it could also be my implementation.

Algernon , 2 days ago (modified 2 days ago)
@Larrian: What's the time complexity of this tool? Playing around with it, it seems to drastically slow when sampling outside of nearby chunks, but it could also be my implementation.

Every sample should take around 1-2ms each on average

Theres no time/space scaling, but it has to generate the region maps before sampling within that region. So the first sample on a fresh region is slower

 

Also im open sourcing it today so you'll be able to check it out

Larrian, 1 day ago
@Algernon: Every sample should take around 1-2ms each on average Theres no time/space scaling, but it has to generate the region maps before sampling within that region. So the first sample on a fresh region is slower Also im open sourcing it today so you'll be able

Seeing the source has helped, thank you! I wonder if it would be worth implementing a method that just samples straight from the terrain noise, without evaluating each region alongside upheaval and ocean noise. That would allow for rapidly generating visualisations of generated worlds across large resolutions. As it is, the region map generation is a pretty big bottleneck (though a necessary one with the current implementation).

Algernon , 1 day ago
@Larrian: Seeing the source has helped, thank you! I wonder if it would be worth implementing a method that just samples straight from the terrain noise, without evaluating each region alongside upheaval and ocean noise. That would allow for rapidly generating visu

Upheaval and ocean noise both have very large impacts on the terrain shape, unless you have 0% upheaval and no oceans, same with the other maps, except maybe the geo map.

There's definitely room to optimise the region map generation for the sampler if you want to add your own GetBlockColumnHeight method variant to it.
You could put stopwatch profiling around each region map's generation to find the bottleneck, then edit the slow region map's scale to be lower resolution, hot reload it in, then check how much the terrain deviates or at all with a cheaper lower res. Or you could try get into the algebra and optimise the actual region noise.

 
chrisunfocused, May 9th at 10:12 AM

Algernon
I have added support for this to Fast Map v5 experimental to pregenerate map tiles.
It's pretty insane. Very nice lib you've put together here.
https://mods.vintagestory.at/show/mod/48907



MischievousCloud, May 5th at 5:51 PM

Is this mod drop in compatible with farseer to see improvements? Or do I need to alter some files to make it work?

MischievousCloud, May 5th at 7:09 PM
@Algernon: Just enable this mod and it'l make Farseer faster and more stable

Oh man, I am so glad you pointed this out to me on the other post :) Thanks a ton!

SeniLiX, May 3rd at 12:57 PM (modified May 3rd at 12:57 PM)

How did I not find this mod before now?

I'm using Farseer and was struggling with random 1 second lockups when exploring.

After installing this, it's just butter smooth! 😄

Thank you so much!

Algernon , May 3rd at 6:04 PM
@SeniLiX: How did I not find this mod before now? I'm using Farseer and was struggling with random 1 second lockups when exploring. After installing this, it's just butter smooth! 😄 Thank you so much!

Yeah it tripped me out the first time I loaded in the game after I hooked farseer into this, multiplied by the fact it just worked first try

Graim, May 1st at 9:38 AM (modified May 1st at 9:41 AM)

This is amazing for inspecting different landform generator mods with farseer and see how the terrain will look like on a large scale. 

Here is a world with these mods: 512 World Height Landforms 128 Sea Level Fork + Continental World.

Settings are: Landocver 30%, Landcover scale 200%, Upheaval 0%, Landform scale 300%, 512 height world with sea level at 128, 1st screenshot taken on y=1000, farseer distance on 16384. 2nd is at y=130.

Algernon , Apr 27th at 9:28 AM

Sparkplug04 JerreyRough Mr_Cookie13

Should be fixed with the newest updates on watersheds and my terrain sampler

Sparkplug04, Apr 27th at 4:26 AM

Algernon Thanks for the update! Good to see it's working now, though now that I know it is baked into Watersheds, I guess it is redundant when used together.

321BoltsOfLight, Apr 27th at 4:04 AM

Thanks for the awesome mod! I love the performance increase in Farseer

JerreyRough, Apr 27th at 1:52 AM

There's an error in Watersheds in the client-main when both are enabled. The world still loads but idk if this will stop watersheds from working?

 

Crash Report
26.4.2026 18:46:01 [Error] [watersheds] An exception was thrown when trying to load assembly:
26.4.2026 18:46:01 [Error] [watersheds] Exception: Could not load file or assembly 'Microsoft.Extensions.Caching.Abstractions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. Assembly with same name is already loaded
at System.Runtime.Loader.AssemblyLoadContext.<LoadFromPath>g____PInvoke|5_0(IntPtr __ptrNativeAssemblyBinder_native, UInt16* __ilPath_native, UInt16* __niPath_native, ObjectHandleOnStack __retAssembly_native)
at System.Runtime.Loader.AssemblyLoadContext.<LoadFromPath>g____PInvoke|5_0(IntPtr __ptrNativeAssemblyBinder_native, UInt16* __ilPath_native, UInt16* __niPath_native, ObjectHandleOnStack __retAssembly_native)
at System.Reflection.Assembly.LoadFrom(String assemblyFile)
at System.Linq.Enumerable.ListSelectIterator`2.MoveNext()
at System.Linq.Enumerable.IEnumerableWhereIterator`1.ToList()
at Vintagestory.Common.ModContainer.LoadAssembly(ModCompilationContext compilationContext, ModAssemblyLoader loader) in VintagestoryLib\Common\API\ModContainer.cs:line 595
Algernon , Apr 27th at 12:54 AM (modified Apr 27th at 1:12 AM)

CG23Sailor Sparkplug04 Mr_Cookie13 Haven't looked at this lib in awhile. There's been some updates to watersheds since then, so now its getting used I'll try make sure they're working together again today

Edit: works for me with watersheds 6.0.5

https://i.imgur.com/mmHqeyG.png

Mr_Cookie13, Apr 26th at 8:39 PM

Sparkplug04 just tested it with Watersheds it's incompatible.

Sparkplug04, Apr 26th at 8:07 PM

Adding to that question from Sailor, this isn't incompatible with Watersheds, right? Or would it be redundant?
The wording has me confused.

CG23Sailor, Apr 26th at 6:18 PM

I just came here after seeing the update to farseer.

You say here that this originally comes from your watershed mod, which I have.
I came here to get this for farseer, but do I need to if I have Watershed?

MystiVaid, Apr 16th at 1:58 PM

image

I don't know why, but Rider prompts that `"TerrainSamplerMod.Instance" is only supported on "Windows" version 7.0 and above.`

However, since this feature can only be used on the server side, it cannot replace `BlockAccessor.GetRainMapHeightAt` when adding path points on the minimap, as the latter is purely client-side.

 
 

 

 

Algernon , Apr 16th at 10:40 PM (modified Apr 16th at 11:01 PM)
@MystiVaid: I don't know why, but Rider prompts that `"TerrainSamplerMod.Instance" is only supported on "Windows" version 7.0 and above.` However, since this feature can only be used on the server side, it cannot replace `BlockAccessor.GetRainMapHeightAt` when adding

Unlucky. Yeah the client only knows about already loaded worldgen, the server deals with unloaded/ungenerated worldgen

You could still query the server to do the calculation for you though

MystiVaid, Apr 16th at 6:37 AM

Wait, is `AlgernonsTerrainSampler.TerrainSamplerMod.Instance.GetBlockColumnHeight` only available on Windows and the server side?

Algernon , Apr 16th at 7:47 AM
@MystiVaid: Wait, is `AlgernonsTerrainSampler.TerrainSamplerMod.Instance.GetBlockColumnHeight` only available on Windows and the server side?

Don't know why this would be windows-only, its all normal .NET code, no extra libraries used

Worldgen is serverside so this worldgen sampling has to be on the server. If you want clients to get the samples, you have to have the clients ask the server to do the sampling

MystiVaid, Apr 16th at 5:13 AM

Can this replace `BlockAccessor.GetRainMapHeightAt`? When adding waypoints on the minimap, the original game uses `BlockAccessor.GetRainMapHeightAt` to obtain the y-coordinate at the mouse position, but it fails to correctly retrieve the y-coordinate for unloaded or already unloaded chunks.

Algernon , Apr 16th at 5:58 AM
@MystiVaid: Can this replace `BlockAccessor.GetRainMapHeightAt`? When adding waypoints on the minimap, the original game uses `BlockAccessor.GetRainMapHeightAt` to obtain the y-coordinate at the mouse position, but it fails to correctly retrieve the y-coordinate for

Pretty sure things like trees and bushes impact the rain height map, so you can't check a single coordinate in isolation to get it perfect

As a fallback for unloaded/ungenerated chunks, the next best thing you could do is first use this sampler to get the terrain height, then clamp to min sealevel. You won't get the accurate rainmap height where theres ponds bushes and trees, but it will still follow the sea/ocean and terrain.

Algernon , Mar 26th at 10:49 PM

SiiMeR Could even get colours if you sample the climate map as well

SiiMeR, Mar 26th at 2:35 PM

You could actually make a mapgenerator preview from this that shows the general world shape if you combine it with the sea height