Access noise in game

Place to get help with not working mods / modding interface.
Post Reply
Mabbus
Manual Inserter
Manual Inserter
Posts: 3
Joined: Sun Apr 24, 2016 1:05 pm
Contact:

Access noise in game

Post by Mabbus »

Hi. I´m making a mod and need to customize the map generation (for something like a world map in an rpg).
I read up some on NoiseExpression, and on perlin noise functions.
https://wiki.factorio.com/Types/NoiseExpression

My instinctive plan was to define some noise layers, for example "myElevation", "moist" and "forest".
Then factorio would do the heavy perlin noise calculations, saving me computing power and actually having to write the complicated perlin noise functions.
Then in "on_chunk_generated" in control.lua I could read the values for my custom noise layers for each tile, and decide what tile to to place from that.

But i cannot find how to get the value of noise layers for a tile in control.lua. Is it possible?

My thought was to do something like
moist > 0.8 = grass-3
0.8 > moist > 0.6 = grass-2
0.6 > moist > 0.4 = grass-1
0.4 > moist > 0.2 = sand-3
0.2 > moist > 0.0 = sand-2
....
Overriding this would be patches of dirt full of trees, representing forest
And overriding this would be red-dirt with rocks, representing mountains


Is something like this possible by defining custom functions for existing noise layers?

I don't fully understand how the noise layer works in vanilla. Instead of the way I wrote above it seem to use a separate function for each tile type. So which tile is then placed? The one whose function returns the greatest value?

I also don't understand why you would create a new noise layer, when only the predefined ones actually affect what tiles are placed?
Any noise gurus here?

FuryoftheStars
Smart Inserter
Smart Inserter
Posts: 2566
Joined: Tue Apr 25, 2017 2:01 pm
Contact:

Re: Access noise in game

Post by FuryoftheStars »

I’m not sure, but try taking a look at Alien Biomes. It adds new tile types and and what have you and has the game generate them with their own regions, etc.
My Mods: Classic Factorio Basic Oil Processing | Sulfur Production from Oils | Wood to Oil Processing | Infinite Resources - Normal Yield | Tree Saplings (Redux) | Alien Biomes Tweaked | Restrictions on Artificial Tiles

Mabbus
Manual Inserter
Manual Inserter
Posts: 3
Joined: Sun Apr 24, 2016 1:05 pm
Contact:

Re: Access noise in game

Post by Mabbus »

Thanks for the tip. I have looked at a few different mods that alter the terrain. Many seem to write their own noise function in lua and then overwrite on_chunk_generated with their custom code. I would like to avoid having to do my own noise functions.
I wasn't able to understand how Alien Biomes does its magic, there is a lot of code to go through there, but I think it basicly added more tiletypes in the data phase and let factorio place them like they place the normal tiles. I might try to look deeper into that mod thou in case it alters the noise functions too.

I did manage to do what I wanted with the help of TOGoS exelent tutorial
https://togos.github.io/togos-example-noise-programs/

The code bellow removes all entities, cliffs and all tiles except sand-1 and dirt-4.
Then it sets the probability for sand to a factorio noise function, and probability for dirt to a constant -0.1
All the tiles where the probability function return > -0.1 will be sand, the rest dirt.
I think this will let me design the functions I need in data.lua.
I still would like to know how to get the value of the probability function for a given tile thou, I can just see
if its bigger then -0,1 or not by what tile is generated.
It would be nice to see the actual values when testing out formulas, and they could be usefull in my mod.

Data.lua

Code: Select all

local noise = require("noise")
local tne = noise.to_noise_expression
data:extend{
  {
    type = "noise-expression",
    name = "myNoise",
    intended_property = "elevation",
    expression = {
      type = "function-application",
      function_name = "factorio-basis-noise",
      arguments = {
        x = noise.var("x"),
        y = noise.var("y"),
        seed0 = tne(noise.var("map_seed")), -- i.e. map.seed
        seed1 = tne(123), -- Some random number
        input_scale = noise.var("segmentation_multiplier")/20,
        output_scale = 20/noise.var("segmentation_multiplier")}}}}
Control.lua

Code: Select all

script.on_init(function()
	local surface = game.surfaces[1]
	surface.clear(true)
	local mgs = surface.map_gen_settings
	mgs.autoplace_settings["entity"] = {treat_missing_as_default = false, settings = {}}
	mgs.autoplace_settings["tile"] = {treat_missing_as_default = false, settings = {["dirt-4"] = 0, ["sand-1"] = 0}}
	mgs.cliff_settings = {cliff_elevation_0 = 1024}
	mgs.property_expression_names["tile:dirt-4:probability"] = -0.1
	mgs.property_expression_names["tile:sand-1:probability"] = "myNoise"
	surface.map_gen_settings = mgs
end)
Image

FuryoftheStars
Smart Inserter
Smart Inserter
Posts: 2566
Joined: Tue Apr 25, 2017 2:01 pm
Contact:

Re: Access noise in game

Post by FuryoftheStars »

It’s very possible the noise functions used by Factorio are not exposed for modding.

I would check out the data\core\ folder, though. My money would be on the functions being in there if it isn’t compiled into the exe.
My Mods: Classic Factorio Basic Oil Processing | Sulfur Production from Oils | Wood to Oil Processing | Infinite Resources - Normal Yield | Tree Saplings (Redux) | Alien Biomes Tweaked | Restrictions on Artificial Tiles

Bilka
Factorio Staff
Factorio Staff
Posts: 3140
Joined: Sat Aug 13, 2016 9:20 am
Contact:

Re: Access noise in game

Post by Bilka »

Mabbus wrote:
Wed Aug 24, 2022 5:37 pm
I still would like to know how to get the value of the probability function for a given tile thou
You can use LuaSurface::calculate_tile_properties
for that. An example for a mod that uses it: https://mods.factorio.com/mod/contour

To be able to use your new named noise expressions in that function there are some conditions:
TOGoS wrote:
Wed Jun 26, 2019 11:12 pm
Probability and richness of any tile, entity, or decorative, and any tile property referenced by them (e.g. elevation, temperature, moisture, cliffiness) or explicitly listed in map gen settings.property_expression_names
So just creating the named noise expression isn't enough, you also have to use it somewhere. A very easy way to do that is to just put it in some random place in the map_gen_settings.property_expression_names. Example command (based on code by Honktown, originally posted on discord):

Code: Select all

/c
local nauvis = game.surfaces.nauvis
local mgs = nauvis.map_gen_settings
mgs.property_expression_names = mgs.property_expression_names or {}
mgs.property_expression_names["some random string"] = "name of your named noise expression"
nauvis.map_gen_settings = mgs
local props = nauvis.calculate_tile_properties(
    {"some random string"},
    {
        {0, 0}
    }
)
game.print(serpent.block(props))


However, no on chunk generated code should be needed for what you describe in your first post. Make your named noise expression like you do in data.lua in your latest post. Then, still in data lua, assign it to the probability_expression of the autoplace of the tile you want to change:

Code: Select all

data.raw.tile["sand-1"].autoplace.probability_expression = noise.var("myNoise")
data.raw.tile["dirt-4"].autoplace.probability_expression = tne(-0.1)
This has the same effect on tile generation as two property_expression_names you set in the control.lua code in your latest post. Since noise expressions have functions for comparisons, you can also implement this:
Mabbus wrote:
Tue Aug 23, 2022 4:04 pm
moist > 0.8 = grass-3
0.8 > moist > 0.6 = grass-2
0.6 > moist > 0.4 = grass-1
0.4 > moist > 0.2 = sand-3
0.2 > moist > 0.0 = sand-2
less-than returns 0 or 1 depending on the condition. So multiplying that with the noise will give you 0 or noise depending on the condition.
data.lua

Code: Select all

data.raw.tile["grass-3"].autoplace.probability_expression = noise.less_than(0.8, noise.var("myNoise")) * noise.var("myNoise")
data.raw.tile["grass-2"].autoplace.probability_expression = noise.less_than(0.6, noise.var("myNoise")) * noise.less_or_equal(noise.var("myNoise"), 0.8) * noise.var("myNoise")
data.raw.tile["grass-1"].autoplace.probability_expression = noise.less_than(0.4, noise.var("myNoise")) * noise.less_or_equal(noise.var("myNoise"), 0.6) * noise.var("myNoise")
data.raw.tile["sand-3"].autoplace.probability_expression = noise.less_than(0.2, noise.var("myNoise")) * noise.less_or_equal(noise.var("myNoise"), 0.4) * noise.var("myNoise")
data.raw.tile["sand-2"].autoplace.probability_expression = noise.less_or_equal(noise.var("myNoise"), 0.2) * noise.var("myNoise")
Right now the code during runtime init is still needed to prevent entities and other tiles below/at 0 probability from spawning. But you can get rid of that too if you remove the spawning probability from the other tiles/entities in the data stage. It's all defined in the autoplace properties of the prototypes.

Currently still needed control.lua

Code: Select all

script.on_init(function()
    local surface = game.surfaces[1]
    surface.clear(true)
    local mgs = surface.map_gen_settings
    mgs.autoplace_settings["entity"] = {treat_missing_as_default = false, settings = {}}
    mgs.autoplace_settings["tile"] = {treat_missing_as_default = false, settings = {["grass-3"] = 0, ["grass-2"] = 0, ["grass-1"] = 0, ["sand-3"] = 0, ["sand-2"] = 0}}
    mgs.cliff_settings = {cliff_elevation_0 = 1024}
    surface.map_gen_settings = mgs
end)
I'm an admin over at https://wiki.factorio.com. Feel free to contact me if there's anything wrong (or right) with it.

Post Reply

Return to “Modding help”